Skip to content

Commit 91741e4

Browse files
authored
Merge pull request #75 from TypingMind/plugin-notion-database
[Notion Database Plugins] Add APIs to handle notion database actions
2 parents add3ac0 + fbad22f commit 91741e4

File tree

7 files changed

+1082
-0
lines changed

7 files changed

+1082
-0
lines changed

package-lock.json

Lines changed: 73 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"dependencies": {
2121
"@asteasolutions/zod-to-openapi": "^7.3.0",
2222
"@mozilla/readability": "^0.5.0",
23+
"@notionhq/client": "^2.2.15",
2324
"@types/got": "^9.6.12",
2425
"@types/jsdom": "^21.1.6",
2526
"body-parser": "^1.20.2",

src/api-docs/openAPIDocumentGenerator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { OpenApiGeneratorV3, OpenAPIRegistry } from '@asteasolutions/zod-to-open
22

33
import { excelGeneratorRegistry } from '@/routes/excelGenerator/excelGeneratorRouter';
44
import { healthCheckRegistry } from '@/routes/healthCheck/healthCheckRouter';
5+
import { notionDatabaseRegistry } from '@/routes/notionDatabase/notionDatabaseRouter';
56
import { powerpointGeneratorRegistry } from '@/routes/powerpointGenerator/powerpointGeneratorRouter';
67
import { articleReaderRegistry } from '@/routes/webPageReader/webPageReaderRouter';
78
import { wordGeneratorRegistry } from '@/routes/wordGenerator/wordGeneratorRouter';
@@ -15,6 +16,7 @@ export function generateOpenAPIDocument() {
1516
powerpointGeneratorRegistry,
1617
wordGeneratorRegistry,
1718
excelGeneratorRegistry,
19+
notionDatabaseRegistry,
1820
]);
1921
const generator = new OpenApiGeneratorV3(registry.definitions);
2022

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
2+
import { z } from 'zod';
3+
4+
extendZodWithOpenApi(z);
5+
6+
// Define Notion Database Structure Reader
7+
export type NotionDatabaseStructureViewerResponse = z.infer<typeof NotionDatabaseStructureViewerResponseSchema>;
8+
export const NotionDatabaseStructureViewerResponseSchema = z.object({});
9+
// Request Body Schema
10+
export const NotionDatabaseStructureViewerRequestBodySchema = z.object({
11+
databaseId: z.string().openapi({
12+
description: 'The ID of the Notion database whose structure is being viewed.',
13+
}),
14+
notionApiKey: z.string().openapi({
15+
description:
16+
'The Notion API Key getting from Notion Integration Page at https://www.notion.so/profile/integrations',
17+
}),
18+
});
19+
export type NotionDatabaseStructureViewerRequestBody = z.infer<typeof NotionDatabaseStructureViewerRequestBodySchema>;
20+
21+
// Define Notion Database Create
22+
export type NotionDatabaseCreatePageResponse = z.infer<typeof NotionDatabaseCreatePageResponseSchema>;
23+
export const NotionDatabaseCreatePageResponseSchema = z.object({});
24+
// Request Body Schema
25+
export const NotionDatabaseCreatePageRequestBodySchema = z.object({
26+
databaseId: z.string().openapi({
27+
description: 'The ID of the Notion database whose structure is being viewed.',
28+
}),
29+
notionApiKey: z.string().openapi({
30+
description:
31+
'The Notion API Key getting from Notion Integration Page at https://www.notion.so/profile/integrations',
32+
}),
33+
properties: z.array(z.object({})),
34+
});
35+
export type NotionDatabaseCreatePageRequestBody = z.infer<typeof NotionDatabaseCreatePageRequestBodySchema>;
36+
37+
// Define Notion Database Update
38+
export type NotionDatabaseUpdatePageResponse = z.infer<typeof NotionDatabaseUpdatePageResponseSchema>;
39+
export const NotionDatabaseUpdatePageResponseSchema = z.object({});
40+
// Request Body Schema
41+
export const NotionDatabaseUpdatePageRequestBodySchema = z.object({
42+
pageId: z.string().openapi({
43+
description: 'The ID of the Notion Page whose structure is being viewed.',
44+
}),
45+
notionApiKey: z.string().openapi({
46+
description:
47+
'The Notion API Key getting from Notion Integration Page at https://www.notion.so/profile/integrations',
48+
}),
49+
properties: z.array(z.object({})),
50+
});
51+
export type NotionDatabaseUpdatePageRequestBody = z.infer<typeof NotionDatabaseUpdatePageRequestBodySchema>;
52+
53+
// Define Notion Database Delete
54+
export type NotionDatabaseArchivePageResponse = z.infer<typeof NotionDatabaseArchivePageResponseSchema>;
55+
export const NotionDatabaseArchivePageResponseSchema = z.object({});
56+
// Request Body Schema
57+
export const NotionDatabaseArchivePageRequestBodySchema = z.object({
58+
pageId: z.string().openapi({
59+
description: 'The ID of the Notion Page whose structure is being viewed.',
60+
}),
61+
notionApiKey: z.string().openapi({
62+
description:
63+
'The Notion API Key getting from Notion Integration Page at https://www.notion.so/profile/integrations',
64+
}),
65+
});
66+
export type NotionDatabaseArchivePageRequestBody = z.infer<typeof NotionDatabaseArchivePageRequestBodySchema>;
67+
68+
// Define Notion Database Query
69+
export type NotionDatabaseQueryPageResponse = z.infer<typeof NotionDatabaseQueryPageResponseSchema>;
70+
export const NotionDatabaseQueryPageResponseSchema = z.object({});
71+
// Request Body Schema
72+
export const NotionDatabaseQueryPageRequestBodySchema = z.object({
73+
databaseId: z.string().openapi({
74+
description: 'The ID of the Notion Database whose structure is being viewed.',
75+
}),
76+
databaseStructure: z
77+
.array(
78+
z.object({
79+
name: z.string().openapi({
80+
description: 'The name of the property.',
81+
}),
82+
type: z
83+
.string()
84+
.openapi({
85+
description: 'The type of the property.',
86+
})
87+
.refine(
88+
(value) =>
89+
[
90+
'title',
91+
'number',
92+
'multi_select',
93+
'select',
94+
'checkbox',
95+
'url',
96+
'status',
97+
'email',
98+
'date',
99+
'files',
100+
'phone_number',
101+
'rich_text',
102+
].includes(value),
103+
{
104+
message: 'Invalid type',
105+
}
106+
),
107+
options: z
108+
.array(
109+
z.object({
110+
name: z.string().openapi({
111+
description: 'Name of the option.',
112+
}),
113+
})
114+
)
115+
.optional()
116+
.openapi({
117+
description: 'List of options for select, multi-select, and status properties.',
118+
}),
119+
})
120+
)
121+
.openapi({
122+
description:
123+
'An array of properties from the Notion database structure, used to generate filter or sort criteria.',
124+
}),
125+
notionApiKey: z.string().openapi({
126+
description:
127+
'The Notion API Key getting from Notion Integration Page at https://www.notion.so/profile/integrations',
128+
}),
129+
query: z.object({}),
130+
sorts: z.array(z.object({})),
131+
pageSize: z.number().optional(),
132+
startCursor: z.any().optional(),
133+
});
134+
export type NotionDatabaseQueryPageRequestBody = z.infer<typeof NotionDatabaseQueryPageRequestBodySchema>;
135+
136+
// Define Notion Database Maker
137+
export type NotionDatabaseMakerResponse = z.infer<typeof NotionDatabaseMakerResponseSchema>;
138+
export const NotionDatabaseMakerResponseSchema = z.object({});
139+
// Request Body Schema
140+
export const NotionDatabaseMakerRequestBodySchema = z.object({
141+
notionApiKey: z.string().openapi({
142+
description:
143+
'The Notion API Key getting from Notion Integration Page at https://www.notion.so/profile/integrations',
144+
}),
145+
parent: z
146+
.object({
147+
type: z.enum(['page_id']),
148+
pageId: z.string().optional(),
149+
databaseId: z.string().optional(),
150+
})
151+
.refine((data) => data.pageId, {
152+
message: 'Page ID must be provided.',
153+
}),
154+
icon: z.string().optional(),
155+
cover: z.string().url().optional(),
156+
isInline: z.boolean().optional(),
157+
title: z
158+
.array(
159+
z.object({
160+
type: z.literal('text'),
161+
text: z
162+
.object({
163+
content: z.string().nonempty('Content is required.'),
164+
})
165+
.required(),
166+
annotations: z
167+
.object({
168+
italic: z.boolean().default(false),
169+
bold: z.boolean().default(false),
170+
color: z.string().default('default'),
171+
strikethrough: z.boolean().default(false),
172+
underline: z.boolean().default(false),
173+
})
174+
.default({
175+
italic: false,
176+
bold: false,
177+
color: 'default',
178+
strikethrough: false,
179+
underline: false,
180+
})
181+
.optional(),
182+
})
183+
)
184+
.nonempty('Title is required.'),
185+
description: z
186+
.array(
187+
z.object({
188+
type: z.literal('text'),
189+
text: z
190+
.object({
191+
content: z.string().nonempty('Content is required.'),
192+
})
193+
.required(),
194+
annotations: z
195+
.object({
196+
italic: z.boolean().default(false),
197+
bold: z.boolean().default(false),
198+
color: z.string().default('default'),
199+
strikethrough: z.boolean().default(false),
200+
underline: z.boolean().default(false),
201+
})
202+
.default({
203+
italic: false,
204+
bold: false,
205+
color: 'default',
206+
strikethrough: false,
207+
underline: false,
208+
})
209+
.optional(),
210+
})
211+
)
212+
.optional(),
213+
notionProperties: z
214+
.array(
215+
z.object({
216+
propertyName: z.string().nonempty('Property name is required.'),
217+
propertyType: z.enum([
218+
'title',
219+
'rich_text',
220+
'number',
221+
'select',
222+
'status',
223+
'multi_select',
224+
'date',
225+
'url',
226+
'email',
227+
'phone_number',
228+
'checkbox',
229+
'files',
230+
'formula',
231+
]),
232+
options: z
233+
.array(
234+
z.object({
235+
name: z.string().nonempty('Option name is required.'),
236+
color: z
237+
.enum(['default', 'gray', 'brown', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'red'])
238+
.optional(),
239+
})
240+
)
241+
.optional(),
242+
format: z
243+
.enum([
244+
'number',
245+
'number_with_commas',
246+
'percent',
247+
'dollar',
248+
'euro',
249+
'pound',
250+
'yen',
251+
'ruble',
252+
'rupee',
253+
'won',
254+
'yuan',
255+
'real',
256+
'lira',
257+
'franc',
258+
'singapore_dollar',
259+
'australian_dollar',
260+
'canadian_dollar',
261+
'hong_kong_dollar',
262+
'new_zealand_dollar',
263+
])
264+
.optional(),
265+
formula: z.string().optional(),
266+
dateFormat: z.string().optional(),
267+
})
268+
)
269+
.nonempty('Notion properties are required.'),
270+
});
271+
export type NotionDatabaseMakerRequestBody = z.infer<typeof NotionDatabaseMakerRequestBodySchema>;

0 commit comments

Comments
 (0)