@keystrokehq/notion 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ import { createNotionClient, withRateLimitRetry } from "./client.mjs";
2
+ import { normalizeListMeta, normalizeSearchResult, notionListResponseSchema, notionSearchResultSchema } from "./schemas.mjs";
3
+ import { t as notionOperation } from "./factory-BttZ5eEq.mjs";
4
+ import { z } from "zod";
5
+
6
+ //#region src/search.ts
7
+ const searchWorkspace = notionOperation({
8
+ id: "search_notion_workspace",
9
+ name: "Search Notion Workspace",
10
+ description: "Search shared Notion pages or data sources by title",
11
+ input: z.object({
12
+ query: z.string().optional(),
13
+ object: z.enum(["page", "data_source"]).optional(),
14
+ sortDirection: z.enum(["ascending", "descending"]).optional(),
15
+ startCursor: z.string().optional(),
16
+ pageSize: z.number().int().positive().max(100).optional()
17
+ }),
18
+ output: notionListResponseSchema(notionSearchResultSchema),
19
+ run: async (input, credentials) => {
20
+ const client = createNotionClient(credentials);
21
+ const response = await withRateLimitRetry(() => client.search({
22
+ ...input.query ? { query: input.query } : {},
23
+ ...input.object ? { filter: {
24
+ property: "object",
25
+ value: input.object
26
+ } } : {},
27
+ sort: {
28
+ timestamp: "last_edited_time",
29
+ direction: input.sortDirection ?? "descending"
30
+ },
31
+ ...input.startCursor ? { start_cursor: input.startCursor } : {},
32
+ ...input.pageSize !== void 0 ? { page_size: input.pageSize } : {}
33
+ }));
34
+ const meta = normalizeListMeta(response);
35
+ return {
36
+ results: response.results.map(normalizeSearchResult),
37
+ hasMore: meta.hasMore,
38
+ nextCursor: meta.nextCursor
39
+ };
40
+ }
41
+ });
42
+
43
+ //#endregion
44
+ export { searchWorkspace };
@@ -0,0 +1,43 @@
1
+ //#region src/shared.ts
2
+ function buildPageParent(parent) {
3
+ if (parent.dataSourceId) return {
4
+ type: "data_source_id",
5
+ data_source_id: parent.dataSourceId
6
+ };
7
+ if (parent.databaseId) return {
8
+ type: "database_id",
9
+ database_id: parent.databaseId
10
+ };
11
+ if (parent.pageId) return {
12
+ type: "page_id",
13
+ page_id: parent.pageId
14
+ };
15
+ throw new Error("Provide one of pageId, databaseId, or dataSourceId.");
16
+ }
17
+ function buildCommentTarget(input) {
18
+ if (input.discussionId) return { discussion_id: input.discussionId };
19
+ if (input.blockId) return { parent: {
20
+ type: "block_id",
21
+ block_id: input.blockId
22
+ } };
23
+ if (input.pageId) return { parent: {
24
+ type: "page_id",
25
+ page_id: input.pageId
26
+ } };
27
+ throw new Error("Provide one of pageId, blockId, or discussionId.");
28
+ }
29
+ function buildPlainTextRichText(content) {
30
+ return [{
31
+ type: "text",
32
+ text: { content }
33
+ }];
34
+ }
35
+ function buildPaginationInput(limit, startCursor) {
36
+ return {
37
+ ...limit !== void 0 ? { page_size: limit } : {},
38
+ ...startCursor ? { start_cursor: startCursor } : {}
39
+ };
40
+ }
41
+
42
+ //#endregion
43
+ export { buildPlainTextRichText as i, buildPageParent as n, buildPaginationInput as r, buildCommentTarget as t };
@@ -0,0 +1,72 @@
1
+ import { n as notion } from "./integration-C7pL009K.mjs";
2
+ import { a as notionWebhookCredentialSet } from "./provider-app-DehoD5sd.mjs";
3
+ import { NotionWebhookEvent, NotionWebhookPayload } from "./events.mjs";
4
+ import { z } from "zod";
5
+ import { BoundTrigger, WebhookRequest } from "@keystrokehq/core";
6
+ import { IntegrationTriggerBindingFactory, IntegrationTriggerBindingOptions } from "@keystrokehq/integration-authoring";
7
+ import { PollingTriggerManifest, WebhookTriggerManifest } from "@keystrokehq/core/trigger";
8
+
9
+ //#region src/triggers.d.ts
10
+ declare const notionPollingBatchSchema: z.ZodObject<{
11
+ results: z.ZodArray<z.ZodObject<{
12
+ eventId: z.ZodString;
13
+ eventType: z.ZodString;
14
+ occurredAt: z.ZodString;
15
+ entityId: z.ZodString;
16
+ entityType: z.ZodString;
17
+ source: z.ZodLiteral<"polling">;
18
+ data: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
19
+ }, z.core.$strip>>;
20
+ hasMore: z.ZodBoolean;
21
+ nextCursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
+ }, z.core.$strip>;
23
+ type NotionPollingBatch = z.output<typeof notionPollingBatchSchema>;
24
+ type NotionWebhookCredentialSets = readonly [typeof notion, typeof notionWebhookCredentialSet];
25
+ type NotionPollingCredentialSets = readonly [typeof notion];
26
+ type NotionWebhookBinding = IntegrationTriggerBindingFactory<NotionWebhookEvent, NotionWebhookCredentialSets, WebhookTriggerManifest, NotionWebhookPayload, WebhookRequest>;
27
+ type NotionPollingBoundTrigger<TOutput> = BoundTrigger<NotionPollingBatch, NotionPollingCredentialSets, PollingTriggerManifest, TOutput>;
28
+ type NotionPollingBindingOptions<TOutput = NotionPollingBatch> = IntegrationTriggerBindingOptions<NotionPollingBatch, TOutput> & {
29
+ readonly schedule?: string;
30
+ };
31
+ type NotionPollingAllPagesOptions<TOutput = NotionPollingBatch> = NotionPollingBindingOptions<TOutput> & {
32
+ readonly query?: string;
33
+ };
34
+ type NotionPollingCommentsOptions<TOutput = NotionPollingBatch> = NotionPollingBindingOptions<TOutput> & {
35
+ readonly blockId: string;
36
+ };
37
+ type NotionPollingDataSourceOptions<TOutput = NotionPollingBatch> = NotionPollingBindingOptions<TOutput> & {
38
+ readonly dataSourceId: string;
39
+ };
40
+ type NotionPollingPageOptions<TOutput = NotionPollingBatch> = NotionPollingBindingOptions<TOutput> & {
41
+ readonly pageId: string;
42
+ };
43
+ type NotionWebhookNamespace = Readonly<{
44
+ pageCreated: NotionWebhookBinding;
45
+ pageContentUpdated: NotionWebhookBinding;
46
+ pagePropertiesUpdated: NotionWebhookBinding;
47
+ pageMoved: NotionWebhookBinding;
48
+ pageDeleted: NotionWebhookBinding;
49
+ pageUndeleted: NotionWebhookBinding;
50
+ pageLocked: NotionWebhookBinding;
51
+ pageUnlocked: NotionWebhookBinding;
52
+ commentCreated: NotionWebhookBinding;
53
+ commentUpdated: NotionWebhookBinding;
54
+ commentDeleted: NotionWebhookBinding;
55
+ dataSourceCreated: NotionWebhookBinding;
56
+ dataSourceContentUpdated: NotionWebhookBinding;
57
+ dataSourceSchemaUpdated: NotionWebhookBinding;
58
+ dataSourceMoved: NotionWebhookBinding;
59
+ dataSourceDeleted: NotionWebhookBinding;
60
+ dataSourceUndeleted: NotionWebhookBinding;
61
+ }>;
62
+ declare const webhooks: NotionWebhookNamespace;
63
+ type NotionPollingNamespace = Readonly<{
64
+ allPageEvents: (options: NotionPollingAllPagesOptions<unknown>) => NotionPollingBoundTrigger<unknown>;
65
+ commentsAdded: (options: NotionPollingCommentsOptions<unknown>) => NotionPollingBoundTrigger<unknown>;
66
+ pageAddedToDataSource: (options: NotionPollingDataSourceOptions<unknown>) => NotionPollingBoundTrigger<unknown>;
67
+ pageAddedToPage: (options: NotionPollingPageOptions<unknown>) => NotionPollingBoundTrigger<unknown>;
68
+ pageUpdated: (options: NotionPollingPageOptions<unknown>) => NotionPollingBoundTrigger<unknown>;
69
+ }>;
70
+ declare const polling: NotionPollingNamespace;
71
+ //#endregion
72
+ export { NotionPollingNamespace, NotionWebhookNamespace, polling, webhooks };
@@ -0,0 +1,285 @@
1
+ import { o as notionWebhookCredentialSet, t as notion } from "./integration-Hfdp-q_v.mjs";
2
+ import { createNotionClient, withRateLimitRetry } from "./client.mjs";
3
+ import { createPollingEvent, normalizeWebhookEvent, notionPollingEventSchema, notionWebhookPayloadSchema } from "./events.mjs";
4
+ import { verifyNotionWebhook } from "./verification.mjs";
5
+ import { z } from "zod";
6
+ import { createPollingTriggerBindingFactory, createWebhookTriggerBindingFactory } from "@keystrokehq/integration-authoring";
7
+
8
+ //#region src/triggers.ts
9
+ const DEFAULT_POLLING_SCHEDULE = "*/10 * * * *";
10
+ const notionPollingBatchSchema = z.object({
11
+ results: z.array(notionPollingEventSchema),
12
+ hasMore: z.boolean(),
13
+ nextCursor: z.string().nullish()
14
+ });
15
+ const notionWebhookCredentialSets = [notion, notionWebhookCredentialSet];
16
+ const notionPollingCredentialSets = [notion];
17
+ function resolveSchedule(schedule) {
18
+ return schedule ?? DEFAULT_POLLING_SCHEDULE;
19
+ }
20
+ function isAfterLastPolled(lastPolledAt, occurredAt) {
21
+ if (!occurredAt) return false;
22
+ if (!lastPolledAt) return true;
23
+ return occurredAt > lastPolledAt;
24
+ }
25
+ function createWebhookBinding(config) {
26
+ return createWebhookTriggerBindingFactory({
27
+ defaultName: config.defaultName,
28
+ defaultDescription: config.defaultDescription,
29
+ path: "/notion",
30
+ method: "POST",
31
+ payload: notionWebhookPayloadSchema,
32
+ credentialSets: notionWebhookCredentialSets,
33
+ verify: (request, ctx) => {
34
+ const webhookCredentials = ctx.credentials["notion-webhook"];
35
+ if (!verifyNotionWebhook({
36
+ headers: request.headers,
37
+ body: request.rawBody
38
+ }, webhookCredentials.verificationToken)) throw new Error("Invalid Notion webhook signature.");
39
+ },
40
+ definitionFilter: (payload) => payload.type === config.eventType,
41
+ mapPayload: (payload) => payload.type === config.eventType ? normalizeWebhookEvent(payload) : null,
42
+ idempotencyKey: (payload) => payload.id,
43
+ response: { successStatus: 200 }
44
+ });
45
+ }
46
+ function createPollingBinding(config) {
47
+ return (options) => createPollingTriggerBindingFactory({
48
+ defaultName: config.defaultName,
49
+ defaultDescription: config.defaultDescription,
50
+ schedule: resolveSchedule(options.schedule),
51
+ credentialSets: notionPollingCredentialSets,
52
+ response: notionPollingBatchSchema,
53
+ poll: (ctx) => config.build(options, {
54
+ credentials: { notion: ctx.credentials.notion },
55
+ lastPolledAt: ctx.lastPolledAt
56
+ }),
57
+ definitionFilter: (payload) => payload.results.length > 0,
58
+ idempotencyKey: (payload) => payload.results[0]?.eventId
59
+ })({
60
+ name: options.name,
61
+ description: options.description,
62
+ filter: options.filter,
63
+ transform: options.transform
64
+ });
65
+ }
66
+ async function pollAllPages(credentials, lastPolledAt, query) {
67
+ const client = createNotionClient(credentials);
68
+ return {
69
+ results: (await withRateLimitRetry(() => client.search({
70
+ ...query ? { query } : {},
71
+ filter: {
72
+ property: "object",
73
+ value: "page"
74
+ },
75
+ sort: {
76
+ timestamp: "last_edited_time",
77
+ direction: "descending"
78
+ },
79
+ page_size: 100
80
+ }))).results.filter((result) => result.object === "page").filter((result) => isAfterLastPolled(lastPolledAt, "last_edited_time" in result ? result.last_edited_time : null)).map((result) => createPollingEvent({
81
+ eventId: `page:${result.id}:${"last_edited_time" in result ? result.last_edited_time : "unknown"}`,
82
+ eventType: "page.discovered",
83
+ occurredAt: "last_edited_time" in result ? result.last_edited_time : (/* @__PURE__ */ new Date()).toISOString(),
84
+ entityId: result.id,
85
+ entityType: "page",
86
+ data: { url: "url" in result ? result.url : void 0 }
87
+ })),
88
+ hasMore: false,
89
+ nextCursor: null
90
+ };
91
+ }
92
+ async function pollCommentsAdded(credentials, lastPolledAt, blockId) {
93
+ const client = createNotionClient(credentials);
94
+ return {
95
+ results: (await withRateLimitRetry(() => client.comments.list({
96
+ block_id: blockId,
97
+ page_size: 100
98
+ }))).results.filter((comment) => isAfterLastPolled(lastPolledAt, comment.created_time)).map((comment) => createPollingEvent({
99
+ eventId: `comment:${comment.id}:${comment.created_time}`,
100
+ eventType: "comment.created",
101
+ occurredAt: comment.created_time,
102
+ entityId: comment.id,
103
+ entityType: "comment",
104
+ data: {
105
+ blockId,
106
+ discussionId: comment.discussion_id
107
+ }
108
+ })),
109
+ hasMore: false,
110
+ nextCursor: null
111
+ };
112
+ }
113
+ async function pollPagesAddedToDataSource(credentials, lastPolledAt, dataSourceId) {
114
+ const client = createNotionClient(credentials);
115
+ return {
116
+ results: (await withRateLimitRetry(() => client.dataSources.query({
117
+ data_source_id: dataSourceId,
118
+ page_size: 100,
119
+ sorts: [{
120
+ timestamp: "created_time",
121
+ direction: "descending"
122
+ }]
123
+ }))).results.filter((page) => "object" in page && page.object === "page" && "created_time" in page).filter((page) => isAfterLastPolled(lastPolledAt, page.created_time)).map((page) => createPollingEvent({
124
+ eventId: `data-source-page:${page.id}:${page.created_time}`,
125
+ eventType: "page.added_to_data_source",
126
+ occurredAt: page.created_time,
127
+ entityId: page.id,
128
+ entityType: "page",
129
+ data: { dataSourceId }
130
+ })),
131
+ hasMore: false,
132
+ nextCursor: null
133
+ };
134
+ }
135
+ async function pollPagesAddedToPage(credentials, lastPolledAt, pageId) {
136
+ const client = createNotionClient(credentials);
137
+ return {
138
+ results: (await withRateLimitRetry(() => client.blocks.children.list({
139
+ block_id: pageId,
140
+ page_size: 100
141
+ }))).results.filter((block) => "type" in block && block.type === "child_page" && "created_time" in block).filter((block) => isAfterLastPolled(lastPolledAt, block.created_time)).map((block) => createPollingEvent({
142
+ eventId: `child-page:${block.id}:${block.created_time}`,
143
+ eventType: "page.added_to_page",
144
+ occurredAt: block.created_time,
145
+ entityId: block.id,
146
+ entityType: "page",
147
+ data: { pageId }
148
+ })),
149
+ hasMore: false,
150
+ nextCursor: null
151
+ };
152
+ }
153
+ async function pollPageUpdated(credentials, lastPolledAt, pageId) {
154
+ const client = createNotionClient(credentials);
155
+ const response = await withRateLimitRetry(() => client.pages.retrieve({ page_id: pageId }));
156
+ return {
157
+ results: "last_edited_time" in response && isAfterLastPolled(lastPolledAt, response.last_edited_time) ? [createPollingEvent({
158
+ eventId: `page-updated:${response.id}:${response.last_edited_time}`,
159
+ eventType: "page.updated",
160
+ occurredAt: response.last_edited_time,
161
+ entityId: response.id,
162
+ entityType: "page",
163
+ data: { url: "url" in response ? response.url : void 0 }
164
+ })] : [],
165
+ hasMore: false,
166
+ nextCursor: null
167
+ };
168
+ }
169
+ const webhooks = Object.freeze({
170
+ pageCreated: createWebhookBinding({
171
+ defaultName: "Notion Page Created",
172
+ defaultDescription: "Fires when Notion creates a page",
173
+ eventType: "page.created"
174
+ }),
175
+ pageContentUpdated: createWebhookBinding({
176
+ defaultName: "Notion Page Content Updated",
177
+ defaultDescription: "Fires when Notion updates page content",
178
+ eventType: "page.content_updated"
179
+ }),
180
+ pagePropertiesUpdated: createWebhookBinding({
181
+ defaultName: "Notion Page Properties Updated",
182
+ defaultDescription: "Fires when Notion updates page properties",
183
+ eventType: "page.properties_updated"
184
+ }),
185
+ pageMoved: createWebhookBinding({
186
+ defaultName: "Notion Page Moved",
187
+ defaultDescription: "Fires when a Notion page moves",
188
+ eventType: "page.moved"
189
+ }),
190
+ pageDeleted: createWebhookBinding({
191
+ defaultName: "Notion Page Deleted",
192
+ defaultDescription: "Fires when Notion deletes a page",
193
+ eventType: "page.deleted"
194
+ }),
195
+ pageUndeleted: createWebhookBinding({
196
+ defaultName: "Notion Page Restored",
197
+ defaultDescription: "Fires when Notion restores a page from trash",
198
+ eventType: "page.undeleted"
199
+ }),
200
+ pageLocked: createWebhookBinding({
201
+ defaultName: "Notion Page Locked",
202
+ defaultDescription: "Fires when Notion locks a page",
203
+ eventType: "page.locked"
204
+ }),
205
+ pageUnlocked: createWebhookBinding({
206
+ defaultName: "Notion Page Unlocked",
207
+ defaultDescription: "Fires when Notion unlocks a page",
208
+ eventType: "page.unlocked"
209
+ }),
210
+ commentCreated: createWebhookBinding({
211
+ defaultName: "Notion Comment Created",
212
+ defaultDescription: "Fires when Notion creates a comment",
213
+ eventType: "comment.created"
214
+ }),
215
+ commentUpdated: createWebhookBinding({
216
+ defaultName: "Notion Comment Updated",
217
+ defaultDescription: "Fires when Notion updates a comment",
218
+ eventType: "comment.updated"
219
+ }),
220
+ commentDeleted: createWebhookBinding({
221
+ defaultName: "Notion Comment Deleted",
222
+ defaultDescription: "Fires when Notion deletes a comment",
223
+ eventType: "comment.deleted"
224
+ }),
225
+ dataSourceCreated: createWebhookBinding({
226
+ defaultName: "Notion Data Source Created",
227
+ defaultDescription: "Fires when Notion creates a data source",
228
+ eventType: "data_source.created"
229
+ }),
230
+ dataSourceContentUpdated: createWebhookBinding({
231
+ defaultName: "Notion Data Source Content Updated",
232
+ defaultDescription: "Fires when Notion updates data-source content",
233
+ eventType: "data_source.content_updated"
234
+ }),
235
+ dataSourceSchemaUpdated: createWebhookBinding({
236
+ defaultName: "Notion Data Source Schema Updated",
237
+ defaultDescription: "Fires when Notion updates data-source schema",
238
+ eventType: "data_source.schema_updated"
239
+ }),
240
+ dataSourceMoved: createWebhookBinding({
241
+ defaultName: "Notion Data Source Moved",
242
+ defaultDescription: "Fires when Notion moves a data source",
243
+ eventType: "data_source.moved"
244
+ }),
245
+ dataSourceDeleted: createWebhookBinding({
246
+ defaultName: "Notion Data Source Deleted",
247
+ defaultDescription: "Fires when Notion deletes a data source",
248
+ eventType: "data_source.deleted"
249
+ }),
250
+ dataSourceUndeleted: createWebhookBinding({
251
+ defaultName: "Notion Data Source Restored",
252
+ defaultDescription: "Fires when Notion restores a data source",
253
+ eventType: "data_source.undeleted"
254
+ })
255
+ });
256
+ const polling = Object.freeze({
257
+ allPageEvents: createPollingBinding({
258
+ defaultName: "Notion All Page Events",
259
+ defaultDescription: "Poll for recently changed Notion pages",
260
+ build: (options, ctx) => pollAllPages(ctx.credentials.notion, ctx.lastPolledAt, options.query)
261
+ }),
262
+ commentsAdded: createPollingBinding({
263
+ defaultName: "Notion Comments Added",
264
+ defaultDescription: "Poll for newly created Notion comments on a block or page",
265
+ build: (options, ctx) => pollCommentsAdded(ctx.credentials.notion, ctx.lastPolledAt, options.blockId)
266
+ }),
267
+ pageAddedToDataSource: createPollingBinding({
268
+ defaultName: "Notion Page Added To Data Source",
269
+ defaultDescription: "Poll for newly created entries in a Notion data source",
270
+ build: (options, ctx) => pollPagesAddedToDataSource(ctx.credentials.notion, ctx.lastPolledAt, options.dataSourceId)
271
+ }),
272
+ pageAddedToPage: createPollingBinding({
273
+ defaultName: "Notion Page Added To Page",
274
+ defaultDescription: "Poll for new child pages added under a Notion page",
275
+ build: (options, ctx) => pollPagesAddedToPage(ctx.credentials.notion, ctx.lastPolledAt, options.pageId)
276
+ }),
277
+ pageUpdated: createPollingBinding({
278
+ defaultName: "Notion Page Updated",
279
+ defaultDescription: "Poll a single Notion page for updates",
280
+ build: (options, ctx) => pollPageUpdated(ctx.credentials.notion, ctx.lastPolledAt, options.pageId)
281
+ })
282
+ });
283
+
284
+ //#endregion
285
+ export { polling, webhooks };
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ import * as _keystrokehq_core0 from "@keystrokehq/core";
3
+ import * as _keystrokehq_core_credential_set0 from "@keystrokehq/core/credential-set";
4
+
5
+ //#region src/users.d.ts
6
+ declare const getMe: _keystrokehq_core0.Operation<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
7
+ id: z.ZodString;
8
+ object: z.ZodLiteral<"user">;
9
+ type: z.ZodString;
10
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
11
+ avatarUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
12
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"notion", z.ZodObject<{
14
+ NOTION_ACCESS_TOKEN: z.ZodString;
15
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
16
+ NOTION_ACCESS_TOKEN: z.ZodString;
17
+ }, z.core.$strip>>[] | undefined>], undefined>;
18
+ declare const getUser: _keystrokehq_core0.Operation<z.ZodObject<{
19
+ userId: z.ZodString;
20
+ }, z.core.$strip>, z.ZodObject<{
21
+ id: z.ZodString;
22
+ object: z.ZodLiteral<"user">;
23
+ type: z.ZodString;
24
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
25
+ avatarUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
26
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"notion", z.ZodObject<{
28
+ NOTION_ACCESS_TOKEN: z.ZodString;
29
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
30
+ NOTION_ACCESS_TOKEN: z.ZodString;
31
+ }, z.core.$strip>>[] | undefined>], undefined>;
32
+ declare const listUsers: _keystrokehq_core0.Operation<z.ZodObject<{
33
+ limit: z.ZodOptional<z.ZodNumber>;
34
+ startCursor: z.ZodOptional<z.ZodString>;
35
+ }, z.core.$strip>, z.ZodObject<{
36
+ results: z.ZodArray<z.ZodObject<{
37
+ id: z.ZodString;
38
+ object: z.ZodLiteral<"user">;
39
+ type: z.ZodString;
40
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
41
+ avatarUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
42
+ email: z.ZodOptional<z.ZodNullable<z.ZodString>>;
43
+ }, z.core.$strip>>;
44
+ hasMore: z.ZodBoolean;
45
+ nextCursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
46
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"notion", z.ZodObject<{
47
+ NOTION_ACCESS_TOKEN: z.ZodString;
48
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
49
+ NOTION_ACCESS_TOKEN: z.ZodString;
50
+ }, z.core.$strip>>[] | undefined>], undefined>;
51
+ //#endregion
52
+ export { getMe, getUser, listUsers };
package/dist/users.mjs ADDED
@@ -0,0 +1,52 @@
1
+ import { createNotionClient, withRateLimitRetry } from "./client.mjs";
2
+ import { normalizeListMeta, normalizeUser, notionListResponseSchema, notionUserSchema } from "./schemas.mjs";
3
+ import { t as notionOperation } from "./factory-BttZ5eEq.mjs";
4
+ import { r as buildPaginationInput } from "./shared-C6A6JPl3.mjs";
5
+ import { z } from "zod";
6
+
7
+ //#region src/users.ts
8
+ const getMe = notionOperation({
9
+ id: "get_notion_me",
10
+ name: "Get Notion Bot User",
11
+ description: "Retrieve the bot user associated with the current Notion token",
12
+ input: z.object({}),
13
+ output: notionUserSchema,
14
+ run: async (_input, credentials) => {
15
+ const client = createNotionClient(credentials);
16
+ return normalizeUser(await withRateLimitRetry(() => client.users.me({})));
17
+ }
18
+ });
19
+ const getUser = notionOperation({
20
+ id: "get_notion_user",
21
+ name: "Get Notion User",
22
+ description: "Retrieve a Notion user by ID",
23
+ input: z.object({ userId: z.string().min(1) }),
24
+ output: notionUserSchema,
25
+ run: async (input, credentials) => {
26
+ const client = createNotionClient(credentials);
27
+ return normalizeUser(await withRateLimitRetry(() => client.users.retrieve({ user_id: input.userId })));
28
+ }
29
+ });
30
+ const listUsers = notionOperation({
31
+ id: "list_notion_users",
32
+ name: "List Notion Users",
33
+ description: "List users visible to the current Notion integration",
34
+ input: z.object({
35
+ limit: z.number().int().positive().max(100).optional(),
36
+ startCursor: z.string().optional()
37
+ }),
38
+ output: notionListResponseSchema(notionUserSchema),
39
+ run: async (input, credentials) => {
40
+ const client = createNotionClient(credentials);
41
+ const response = await withRateLimitRetry(() => client.users.list(buildPaginationInput(input.limit, input.startCursor)));
42
+ const meta = normalizeListMeta(response);
43
+ return {
44
+ results: response.results.map(normalizeUser),
45
+ hasMore: meta.hasMore,
46
+ nextCursor: meta.nextCursor
47
+ };
48
+ }
49
+ });
50
+
51
+ //#endregion
52
+ export { getMe, getUser, listUsers };
@@ -0,0 +1,18 @@
1
+ //#region src/verification.d.ts
2
+ /**
3
+ * notion/verification.ts
4
+ *
5
+ * Notion webhook signature verification.
6
+ *
7
+ * Notion signs webhook requests using HMAC-SHA256 with the verification token.
8
+ * Delegates the HMAC plumbing to the shared `verifyHmacWebhook` helper.
9
+ *
10
+ * Header: `x-notion-signature`: `sha256=<hex-digest>`
11
+ * Signature: `HMAC-SHA256(verificationToken, <raw body>)`
12
+ */
13
+ declare function verifyNotionWebhook(request: {
14
+ headers: Record<string, string | string[] | undefined>;
15
+ body: string | Buffer;
16
+ }, verificationToken: string): boolean;
17
+ //#endregion
18
+ export { verifyNotionWebhook };
@@ -0,0 +1,24 @@
1
+ import { verifyHmacWebhook } from "@keystrokehq/integration-authoring/webhooks";
2
+
3
+ //#region src/verification.ts
4
+ /**
5
+ * notion/verification.ts
6
+ *
7
+ * Notion webhook signature verification.
8
+ *
9
+ * Notion signs webhook requests using HMAC-SHA256 with the verification token.
10
+ * Delegates the HMAC plumbing to the shared `verifyHmacWebhook` helper.
11
+ *
12
+ * Header: `x-notion-signature`: `sha256=<hex-digest>`
13
+ * Signature: `HMAC-SHA256(verificationToken, <raw body>)`
14
+ */
15
+ function verifyNotionWebhook(request, verificationToken) {
16
+ return verifyHmacWebhook(request, {
17
+ secret: verificationToken,
18
+ signatureHeader: "x-notion-signature",
19
+ signaturePrefix: "sha256="
20
+ });
21
+ }
22
+
23
+ //#endregion
24
+ export { verifyNotionWebhook };