Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP #85

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

WIP #85

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .editorconfig

This file was deleted.

40 changes: 36 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,36 @@
dist
node_modules
worker
wrangler.toml
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
11 changes: 0 additions & 11 deletions .prettierrc

This file was deleted.

7 changes: 0 additions & 7 deletions LICENSE.md

This file was deleted.

12 changes: 12 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
File renamed without changes.
10 changes: 3 additions & 7 deletions src/api/types.ts → app/notion-api/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Params } from "tiny-request-router";
import { Context } from "hono";


type BoldFormatType = ["b"];
type ItalicFormatType = ["i"];
Expand Down Expand Up @@ -201,9 +202,4 @@ export interface NotionSearchResultsType {
total: number;
}

export interface HandlerRequest {
params: Params;
searchParams: URLSearchParams;
request: Request;
notionToken?: string;
}
export type HandlerRequest = Context
8 changes: 3 additions & 5 deletions src/api/utils.ts → app/notion-api/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ import {
RowType,
} from "./types";

export const idToUuid = (path: string) =>
`${path.slice(0, 8)}-${path.slice(8, 4)}-${path.slice(
12,
4
)}-${path.slice(16, 4)}-${path.slice(20)}`;
export const idToUuid = (path: string): string =>
`${path.slice(0, 8)}-${path.slice(8, 12)}-${path.slice(12, 16)}-${path.slice(16, 20)}-${path.slice(20)}`;

export const parsePageId = (id: string) => {
if (id) {
Expand Down Expand Up @@ -84,3 +81,4 @@ export const getNotionValue = (
const getTextContent = (text: DecorationType[]) => {
return text.reduce((prev, current) => prev + current[0], "");
};

31 changes: 19 additions & 12 deletions src/routes/page.ts → app/routes/notion-page.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { fetchPageById, fetchBlocks } from "../api/notion";
import { parsePageId } from "../api/utils";
import { createResponse } from "../response";
import { fetchPageById, fetchBlocks } from "../notion-api/notion";
import { parsePageId } from "../notion-api/utils";
import { BlockType, CollectionType, HandlerRequest } from "../notion-api/types";
import { getTableData } from "./table";
import { BlockType, CollectionType, HandlerRequest } from "../api/types";
import { createResponse } from "../utils/response";
import { getNotionToken } from "../utils";

export async function pageRoute(req: HandlerRequest) {
const pageId = parsePageId(req.params.pageId);
const page = await fetchPageById(pageId!, req.notionToken);
export async function pageRoute(c: HandlerRequest) {
const pageId = parsePageId(c.req.param("pageId"));
const notionToken = getNotionToken(c);

const page = await fetchPageById(pageId!, notionToken);

const baseBlocks = page.recordMap.block;

Expand Down Expand Up @@ -34,7 +37,7 @@ export async function pageRoute(req: HandlerRequest) {
break;
}

const newBlocks = await fetchBlocks(pendingBlocks, req.notionToken).then(
const newBlocks = await fetchBlocks(pendingBlocks, notionToken).then(
(res) => res.recordMap.block
);

Expand All @@ -55,11 +58,13 @@ export async function pageRoute(req: HandlerRequest) {
const pendingCollections = allBlockKeys.flatMap((blockId) => {
const block = allBlocks[blockId];

return (block.value && block.value.type === "collection_view") ? [block.value.id] : [];
return block.value && block.value.type === "collection_view"
? [block.value.id]
: [];
});

for (let b of pendingCollections) {
const collPage = await fetchPageById(b!, req.notionToken);
const collPage = await fetchPageById(b!, notionToken);

const coll = Object.keys(collPage.recordMap.collection).map(
(k) => collPage.recordMap.collection[k]
Expand All @@ -74,7 +79,7 @@ export async function pageRoute(req: HandlerRequest) {
const { rows, schema } = await getTableData(
coll,
collView.value.id,
req.notionToken,
notionToken,
true
);

Expand All @@ -95,5 +100,7 @@ export async function pageRoute(req: HandlerRequest) {
}
}

return createResponse(allBlocks);
return createResponse(allBlocks, {
request: c,
});
}
37 changes: 37 additions & 0 deletions app/routes/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { fetchNotionSearch } from "../notion-api/notion";
import { HandlerRequest } from "../notion-api/types";
import { parsePageId } from "../notion-api/utils";
import { getNotionToken } from "../utils";
import { createResponse } from "../utils/response";

export async function searchRoute(c: HandlerRequest) {
const notionToken = getNotionToken(c);

const ancestorId = parsePageId(c.req.query("ancestorId") || "");
const query = c.req.query("query") || "";
const limit = Number(c.req.query("limit") || 20);

if (!ancestorId) {
return createResponse(
{ error: 'missing required "ancestorId"' },
{
headers: { "Content-Type": "application/json" },
statusCode: 400,
request: c,
}
);
}

const results = await fetchNotionSearch(
{
ancestorId,
query,
limit,
},
notionToken
);

return createResponse(results, {
request: c,
});
}
34 changes: 20 additions & 14 deletions src/routes/table.ts → app/routes/table.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { fetchPageById, fetchTableData, fetchNotionUsers } from "../api/notion";
import { parsePageId, getNotionValue } from "../api/utils";
import {
fetchPageById,
fetchTableData,
fetchNotionUsers,
} from "../notion-api/notion";
import { parsePageId, getNotionValue } from "../notion-api/utils";
import {
RowContentType,
CollectionType,
RowType,
HandlerRequest,
} from "../api/types";
import { createResponse } from "../response";
} from "../notion-api/types";
import { createResponse } from "../utils/response";
import { getNotionToken } from "../utils";

export const getTableData = async (
collection: CollectionType,
Expand All @@ -23,9 +28,10 @@ export const getTableData = async (
const collectionRows = collection.value.schema;
const collectionColKeys = Object.keys(collectionRows);

const tableArr: RowType[] = table.result.reducerResults.collection_group_results.blockIds.map(
(id: string) => table.recordMap.block[id]
);
const tableArr: RowType[] =
table.result.reducerResults.collection_group_results.blockIds.map(
(id: string) => table.recordMap.block[id]
);

const tableData = tableArr.filter(
(b) =>
Expand Down Expand Up @@ -56,15 +62,15 @@ export const getTableData = async (
return { rows, schema: collectionRows };
};

export async function tableRoute(req: HandlerRequest) {
const pageId = parsePageId(req.params.pageId);
const page = await fetchPageById(pageId!, req.notionToken);
export async function tableRoute(c: HandlerRequest) {
const pageId = parsePageId(c.req.param("pageId"));
const notionToken = getNotionToken(c);
const page = await fetchPageById(pageId!, notionToken);

if (!page.recordMap.collection)
return createResponse(
JSON.stringify({ error: "No table found on Notion page: " + pageId }),
{},
401
{ headers: {}, statusCode: 401, request: c }
);

const collection = Object.keys(page.recordMap.collection).map(
Expand All @@ -80,8 +86,8 @@ export async function tableRoute(req: HandlerRequest) {
const { rows } = await getTableData(
collection,
collectionView.value.id,
req.notionToken
notionToken
);

return createResponse(rows);
return createResponse(rows, { request: c });
}
13 changes: 13 additions & 0 deletions app/routes/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { fetchNotionUsers } from "../notion-api/notion";
import { HandlerRequest } from "../notion-api/types";
import { getNotionToken } from "../utils";
import { createResponse } from "../utils/response";

export async function userRoute(c: HandlerRequest) {
const users = await fetchNotionUsers(
[c.req.param("userId")],
getNotionToken(c)
);

return createResponse(users[0], { request: c });
}
6 changes: 6 additions & 0 deletions app/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { HandlerRequest } from "../notion-api/types";

export const getNotionToken = (c: HandlerRequest) => {
return process.env.NOTION_TOKEN || (c.req.header("Authorization") || "").split("Bearer ")[1] || undefined;

}
26 changes: 26 additions & 0 deletions app/utils/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { HandlerRequest, JSONData } from "../notion-api/types";

export const createResponse = (
body: JSONData | any,
{
headers,
statusCode,
request,
}: {
request: HandlerRequest;
headers?: { [key: string]: string };
statusCode?: number;
}
) => {
const cacheControl = request.req.header("Cache-Control");
return new Response(JSON.stringify(body), {
status: statusCode || 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Content-Type": "application/json",
"Cache-Control": cacheControl || "public, max-age=3600",
...headers,
},
});
};
17 changes: 17 additions & 0 deletions app/v1/[[...route]]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Hono } from "hono";
import { handle } from "hono/vercel";

import { pageRoute } from "../../routes/notion-page";
import { tableRoute } from "../../routes/table";
import { userRoute } from "../../routes/user";
import { searchRoute } from "../../routes/search";

const app = new Hono().basePath("/v1");

app.get("/page/:pageId", pageRoute);
app.get("/table/:pageId", tableRoute);
app.get("/user/:userId", userRoute);
app.get("/search", searchRoute);

export const GET = handle(app);
export const POST = handle(app);
4 changes: 4 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
Loading