@notionhq/workers 0.1.0 → 0.3.0

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.
Files changed (67) hide show
  1. package/dist/ajv-formats.d.js +0 -0
  2. package/dist/capabilities/ai_connector.d.ts +97 -0
  3. package/dist/capabilities/ai_connector.d.ts.map +1 -0
  4. package/dist/capabilities/ai_connector.js +54 -0
  5. package/dist/capabilities/ai_connector.test.d.ts +2 -0
  6. package/dist/capabilities/ai_connector.test.d.ts.map +1 -0
  7. package/dist/capabilities/automation.d.ts.map +1 -1
  8. package/dist/capabilities/automation.js +10 -10
  9. package/dist/capabilities/output.d.ts +5 -0
  10. package/dist/capabilities/output.d.ts.map +1 -0
  11. package/dist/capabilities/output.js +10 -0
  12. package/dist/capabilities/stateful-capability.d.ts +30 -0
  13. package/dist/capabilities/stateful-capability.d.ts.map +1 -0
  14. package/dist/capabilities/stateful-capability.js +50 -0
  15. package/dist/capabilities/stateful-capability.test.d.ts +2 -0
  16. package/dist/capabilities/stateful-capability.test.d.ts.map +1 -0
  17. package/dist/capabilities/sync.d.ts +77 -30
  18. package/dist/capabilities/sync.d.ts.map +1 -1
  19. package/dist/capabilities/sync.js +26 -64
  20. package/dist/capabilities/tool.d.ts.map +1 -1
  21. package/dist/capabilities/tool.js +7 -14
  22. package/dist/capabilities/webhook.d.ts +101 -0
  23. package/dist/capabilities/webhook.d.ts.map +1 -0
  24. package/dist/capabilities/webhook.js +47 -0
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -0
  28. package/dist/pacer.d.ts +24 -0
  29. package/dist/pacer.d.ts.map +1 -0
  30. package/dist/pacer.js +14 -0
  31. package/dist/pacer.test.d.ts +2 -0
  32. package/dist/pacer.test.d.ts.map +1 -0
  33. package/dist/pacer_internal.d.ts +13 -0
  34. package/dist/pacer_internal.d.ts.map +1 -0
  35. package/dist/pacer_internal.js +49 -0
  36. package/dist/schema.d.ts +28 -18
  37. package/dist/schema.d.ts.map +1 -1
  38. package/dist/schema.js +2 -2
  39. package/dist/types.d.ts +5 -2
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/worker.d.ts +222 -7
  42. package/dist/worker.d.ts.map +1 -1
  43. package/dist/worker.js +184 -8
  44. package/dist/worker.test.d.ts +2 -0
  45. package/dist/worker.test.d.ts.map +1 -0
  46. package/package.json +7 -2
  47. package/src/ajv-formats.d.ts +7 -0
  48. package/src/capabilities/ai_connector.test.ts +341 -0
  49. package/src/capabilities/ai_connector.ts +194 -0
  50. package/src/capabilities/automation.test.ts +2 -2
  51. package/src/capabilities/automation.ts +10 -6
  52. package/src/capabilities/output.ts +8 -0
  53. package/src/capabilities/stateful-capability.test.ts +25 -0
  54. package/src/capabilities/stateful-capability.ts +87 -0
  55. package/src/capabilities/sync.test.ts +178 -35
  56. package/src/capabilities/sync.ts +63 -100
  57. package/src/capabilities/tool.test.ts +47 -3
  58. package/src/capabilities/tool.ts +7 -6
  59. package/src/capabilities/webhook.ts +148 -0
  60. package/src/index.ts +31 -0
  61. package/src/pacer.test.ts +110 -0
  62. package/src/pacer.ts +25 -0
  63. package/src/pacer_internal.ts +94 -0
  64. package/src/schema.ts +29 -19
  65. package/src/types.ts +4 -2
  66. package/src/worker.test.ts +167 -0
  67. package/src/worker.ts +335 -10
package/dist/worker.d.ts CHANGED
@@ -1,14 +1,142 @@
1
+ import type { AiConnectorArchetype, AiConnectorCapability, AiConnectorConfiguration } from "./capabilities/ai_connector.js";
1
2
  import type { AutomationCapability, AutomationConfiguration, AutomationEvent } from "./capabilities/automation.js";
2
3
  import type { CapabilityContext } from "./capabilities/context.js";
3
4
  import type { NotionManagedOAuthConfiguration, OAuthCapability, OAuthConfiguration, UserManagedOAuthConfiguration } from "./capabilities/oauth.js";
4
5
  import type { SyncCapability, SyncConfiguration } from "./capabilities/sync.js";
5
6
  import type { ToolCapability, ToolConfiguration } from "./capabilities/tool.js";
7
+ import type { WebhookCapability, WebhookConfiguration, WebhookEvent } from "./capabilities/webhook.js";
8
+ import { WebhookVerificationError } from "./capabilities/webhook.js";
9
+ import type { PacerDeclaration } from "./pacer_internal.js";
6
10
  import type { Schema } from "./schema.js";
7
11
  import type { HandlerOptions, JSONValue } from "./types.js";
8
- export type { AutomationConfiguration, AutomationEvent, CapabilityContext, OAuthConfiguration, NotionManagedOAuthConfiguration, UserManagedOAuthConfiguration, SyncConfiguration, ToolConfiguration, };
9
- type Capability = SyncCapability | ToolCapability<any, any> | AutomationCapability | OAuthCapability;
12
+ export type { AutomationConfiguration, AutomationEvent, AiConnectorConfiguration, CapabilityContext, OAuthConfiguration, NotionManagedOAuthConfiguration, UserManagedOAuthConfiguration, SyncConfiguration, ToolConfiguration, WebhookConfiguration, WebhookEvent, };
13
+ export { WebhookVerificationError };
14
+ type Capability = SyncCapability | AiConnectorCapability | ToolCapability<any, any> | AutomationCapability | OAuthCapability | WebhookCapability;
15
+ /**
16
+ * Configuration for a database that Notion creates and manages on behalf
17
+ * of the worker. The database is created on first deploy and its schema
18
+ * is migrated on subsequent deploys.
19
+ */
20
+ export type ManagedDatabaseConfig<PK extends string, S extends Schema<PK>> = {
21
+ type: "managed";
22
+ /**
23
+ * The title for the database when it is first created in Notion.
24
+ *
25
+ * Updating this after the database has been created will not change the
26
+ * title of the database — users may rename it freely.
27
+ */
28
+ initialTitle: string;
29
+ /**
30
+ * The property that serves as the primary key for matching records.
31
+ * Must be a property defined in the schema. The value of this property
32
+ * should match the `key` field on each sync change.
33
+ */
34
+ primaryKeyProperty: PK;
35
+ /**
36
+ * The database schema. Notion will migrate the database to match
37
+ * the given schema on worker deploy.
38
+ */
39
+ schema: S;
40
+ };
41
+ /**
42
+ * Configuration union for all database types.
43
+ * Currently only `"managed"` is supported.
44
+ */
45
+ export type DatabaseConfig<PK extends string, S extends Schema<PK>> = ManagedDatabaseConfig<PK, S>;
46
+ /**
47
+ * An opaque handle returned by `worker.database()`. Pass this to
48
+ * `worker.sync()` to associate a sync capability with the database.
49
+ */
50
+ export type DatabaseHandle<PK extends string, S extends Schema<PK>> = {
51
+ readonly key: string;
52
+ readonly config: DatabaseConfig<PK, S>;
53
+ };
54
+ /** Internal type-erased alias for storing heterogeneous databases. */
55
+ type RegisteredDatabase = DatabaseHandle<string, Schema<string>>;
56
+ /**
57
+ * Configuration for a pacer that rate-limits requests to an external API.
58
+ * If multiple syncs share a pacer, the server apportions the budget evenly.
59
+ */
60
+ export type PacerConfig = {
61
+ /** Maximum number of requests allowed per interval. */
62
+ allowedRequests: number;
63
+ /** The interval window in milliseconds. */
64
+ intervalMs: number;
65
+ };
66
+ /**
67
+ * An opaque handle returned by `worker.pacer()`. Call `handle.wait()`
68
+ * before each API request to stay under the rate limit.
69
+ */
70
+ export type PacerHandle = {
71
+ readonly key: string;
72
+ readonly config: PacerConfig;
73
+ /**
74
+ * Wait until a request can proceed under this pacer's rate limit.
75
+ *
76
+ * Call this before **every** API request inside your sync's `execute` function.
77
+ * The pacer ensures requests are evenly spaced over the interval window.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const apiPacer = worker.pacer("myApi", { allowedRequests: 10, intervalMs: 1000 });
82
+ *
83
+ * worker.sync("mySync", {
84
+ * database: myDb,
85
+ * execute: async () => {
86
+ * await apiPacer.wait();
87
+ * const data = await fetchFromApi();
88
+ * // ...
89
+ * },
90
+ * });
91
+ * ```
92
+ */
93
+ wait(): Promise<void>;
94
+ };
95
+ export type { PacerDeclaration };
96
+ /** A capability entry stripped of its handler, used in the manifest. */
97
+ type CapabilityManifestEntry = Pick<Capability, "_tag" | "key" | "config">;
98
+ /**
99
+ * The full worker manifest, read by the server at deploy time to discover
100
+ * databases, pacers, capabilities, and the SDK version.
101
+ */
102
+ export type WorkerManifest = {
103
+ readonly sdkVersion: string;
104
+ readonly databases: readonly RegisteredDatabase[];
105
+ readonly pacers: readonly PacerDeclaration[];
106
+ readonly capabilities: readonly CapabilityManifestEntry[];
107
+ };
10
108
  export declare class Worker {
11
109
  #private;
110
+ database<PK extends string, S extends Schema<PK>>(key: string, config: DatabaseConfig<PK, S>): DatabaseHandle<PK, S>;
111
+ /**
112
+ * Register a pacer for rate-limiting requests to an external API.
113
+ *
114
+ * Multiple syncs can share a pacer — the server will apportion the
115
+ * budget evenly across all syncs that reference it.
116
+ *
117
+ * Example:
118
+ *
119
+ * ```ts
120
+ * const jiraPacer = worker.pacer("jira", {
121
+ * allowedRequests: 10,
122
+ * intervalMs: 1000,
123
+ * });
124
+ *
125
+ * worker.sync("jiraSync", {
126
+ * database: tasks,
127
+ * execute: async (state, { notion }) => {
128
+ * await jiraPacer.wait();
129
+ * const data = await fetchFromJira();
130
+ * // ...
131
+ * },
132
+ * });
133
+ * ```
134
+ *
135
+ * @param key - The unique key for this pacer.
136
+ * @param config - The rate limit configuration.
137
+ * @returns A pacer handle. Call `handle.wait()` before each API request.
138
+ */
139
+ pacer(key: string, config: PacerConfig): PacerHandle;
12
140
  /**
13
141
  * Register a sync capability.
14
142
  *
@@ -22,26 +150,29 @@ export declare class Worker {
22
150
  * const worker = new Worker();
23
151
  * export default worker;
24
152
  *
25
- * worker.sync("tasksSync", {
26
- * primaryKeyProperty: "Task ID",
153
+ * const tasks = worker.database("tasks", {
154
+ * type: "managed",
155
+ * initialTitle: "Tasks",
27
156
  * schema: {
28
- * defaultName: "Tasks",
29
157
  * properties: {
30
158
  * "Task Name": Schema.title(),
31
- * "Task ID": Schema.richText(),
32
159
  * Status: Schema.select([
33
160
  * { name: "Open", color: "default" },
34
161
  * { name: "Done", color: "green" },
35
162
  * ]),
36
163
  * },
37
164
  * },
165
+ * });
166
+ *
167
+ * worker.sync("tasksSync", {
168
+ * database: tasks,
38
169
  * execute: async () => {
39
170
  * const changes = [
40
171
  * {
41
172
  * key: "task-1",
173
+ * type: "upsert",
42
174
  * properties: {
43
175
  * "Task Name": Builder.title("Write docs"),
44
- * "Task ID": Builder.richText("task-1"),
45
176
  * Status: Builder.select("Open"),
46
177
  * },
47
178
  * },
@@ -57,6 +188,60 @@ export declare class Worker {
57
188
  * @returns The capability object.
58
189
  */
59
190
  sync<PK extends string, S extends Schema<PK>, Context = unknown>(key: string, config: SyncConfiguration<PK, S, Context>): SyncCapability;
191
+ /**
192
+ * Register an AI connector capability.
193
+ *
194
+ * Example:
195
+ *
196
+ * ```ts
197
+ * const worker = new Worker();
198
+ * export default worker;
199
+ *
200
+ * worker.aiConnector("supportChats", {
201
+ * aiConnectorId: "connector-record-id",
202
+ * archetype: "chat",
203
+ * mode: "incremental",
204
+ * schedule: "15m",
205
+ * execute: async (state) => ({
206
+ * changes: [
207
+ * {
208
+ * type: "upsert",
209
+ * key: "thread-1",
210
+ * record: {
211
+ * createdAt: "2026-01-01T00:00:00Z",
212
+ * updatedAt: "2026-01-01T00:00:00Z",
213
+ * channel: {
214
+ * id: "channel-1",
215
+ * name: "Support",
216
+ * },
217
+ * threadId: "thread-1",
218
+ * messages: [
219
+ * {
220
+ * id: "message-1",
221
+ * content: "Hello from support",
222
+ * timestamp: "2026-01-01T00:00:00Z",
223
+ * author: {
224
+ * id: "user-1",
225
+ * username: "alice",
226
+ * },
227
+ * },
228
+ * ],
229
+ * },
230
+ * },
231
+ * ],
232
+ * hasMore: false,
233
+ * }),
234
+ * });
235
+ * ```
236
+ *
237
+ * `aiConnectorId` must be the Notion record ID of an existing custom
238
+ * connector in the workspace where you deploy this worker.
239
+ *
240
+ * @param key - The unique key for this capability.
241
+ * @param config - The AI connector configuration.
242
+ * @returns The capability object.
243
+ */
244
+ aiConnector<A extends AiConnectorArchetype, Context = unknown>(key: string, config: AiConnectorConfiguration<A, Context>): AiConnectorCapability;
60
245
  /**
61
246
  * Register a tool capability.
62
247
  *
@@ -113,6 +298,35 @@ export declare class Worker {
113
298
  * @returns The capability object.
114
299
  */
115
300
  automation(key: string, config: AutomationConfiguration): AutomationCapability;
301
+ /**
302
+ * Register a webhook capability.
303
+ *
304
+ * Webhooks expose an HTTP endpoint that external services can call.
305
+ * When hit, the request is processed by the worker's execute function.
306
+ *
307
+ * Example:
308
+ *
309
+ * ```ts
310
+ * const worker = new Worker();
311
+ * export default worker;
312
+ *
313
+ * worker.webhook("onGithubPush", {
314
+ * title: "GitHub Push Webhook",
315
+ * description: "Handles push events from GitHub",
316
+ * execute: async (events, { notion }) => {
317
+ * for (const event of events) {
318
+ * console.log("Received webhook:", event.body);
319
+ * console.log("Headers:", event.headers);
320
+ * }
321
+ * },
322
+ * })
323
+ * ```
324
+ *
325
+ * @param key - The unique key for this capability. Used as the webhook name in the URL.
326
+ * @param config - The webhook configuration.
327
+ * @returns The capability object.
328
+ */
329
+ webhook(key: string, config: WebhookConfiguration): WebhookCapability;
116
330
  /**
117
331
  * Register an OAuth capability.
118
332
  *
@@ -159,6 +373,7 @@ export declare class Worker {
159
373
  * Get all registered capabilities (for discovery) without their handlers.
160
374
  */
161
375
  get capabilities(): Pick<Capability, "_tag" | "key" | "config">[];
376
+ get manifest(): WorkerManifest;
162
377
  /**
163
378
  * Execute a capability by key.
164
379
  *
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,EACf,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EACX,+BAA+B,EAC/B,eAAe,EACf,kBAAkB,EAClB,6BAA6B,EAC7B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5D,YAAY,EACX,uBAAuB,EACvB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,6BAA6B,EAC7B,iBAAiB,EACjB,iBAAiB,GACjB,CAAC;AAMF,KAAK,UAAU,GACZ,cAAc,GAEd,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,GACxB,oBAAoB,GACpB,eAAe,CAAC;AAMnB,qBAAa,MAAM;;IAGlB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8CG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,EAC9D,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,iBAAiB,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,GACvC,cAAc;IAOjB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,IAAI,CAAC,CAAC,SAAS,SAAS,EAAE,CAAC,SAAS,SAAS,GAAG,SAAS,EACxD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAQvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,UAAU,CACT,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,uBAAuB,GAC7B,oBAAoB;IAOvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAwCG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,eAAe;IAO/D;;OAEG;IACH,IAAI,YAAY,IAAI,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC,EAAE,CAMhE;IAED;;;;;;;OAOG;IACG,GAAG,CACR,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,cAAmB,GAC1B,OAAO,CAAC,OAAO,CAAC;CAyBnB"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
package/dist/worker.js CHANGED
@@ -1,9 +1,69 @@
1
+ import { createAiConnectorCapability } from "./capabilities/ai_connector.js";
1
2
  import { createAutomationCapability } from "./capabilities/automation.js";
2
3
  import { createOAuthCapability } from "./capabilities/oauth.js";
3
4
  import { createSyncCapability } from "./capabilities/sync.js";
4
5
  import { createToolCapability } from "./capabilities/tool.js";
6
+ import {
7
+ createWebhookCapability,
8
+ WebhookVerificationError
9
+ } from "./capabilities/webhook.js";
10
+ import { pacerWait } from "./pacer_internal.js";
11
+ import { createRequire } from "node:module";
12
+ const SDK_VERSION = (() => {
13
+ const require2 = createRequire(import.meta.url);
14
+ const packageJson = require2("../package.json");
15
+ if (typeof packageJson !== "object" || packageJson === null || !("version" in packageJson) || typeof packageJson.version !== "string") {
16
+ throw new Error("Failed to read SDK version from package.json");
17
+ }
18
+ return packageJson.version;
19
+ })();
5
20
  class Worker {
6
21
  #capabilities = /* @__PURE__ */ new Map();
22
+ #databases = /* @__PURE__ */ new Map();
23
+ #pacers = /* @__PURE__ */ new Map();
24
+ database(key, config) {
25
+ this.#validateUniqueKey(key);
26
+ const database = { key, config };
27
+ this.#databases.set(key, { key, config });
28
+ return database;
29
+ }
30
+ /**
31
+ * Register a pacer for rate-limiting requests to an external API.
32
+ *
33
+ * Multiple syncs can share a pacer — the server will apportion the
34
+ * budget evenly across all syncs that reference it.
35
+ *
36
+ * Example:
37
+ *
38
+ * ```ts
39
+ * const jiraPacer = worker.pacer("jira", {
40
+ * allowedRequests: 10,
41
+ * intervalMs: 1000,
42
+ * });
43
+ *
44
+ * worker.sync("jiraSync", {
45
+ * database: tasks,
46
+ * execute: async (state, { notion }) => {
47
+ * await jiraPacer.wait();
48
+ * const data = await fetchFromJira();
49
+ * // ...
50
+ * },
51
+ * });
52
+ * ```
53
+ *
54
+ * @param key - The unique key for this pacer.
55
+ * @param config - The rate limit configuration.
56
+ * @returns A pacer handle. Call `handle.wait()` before each API request.
57
+ */
58
+ pacer(key, config) {
59
+ this.#validateUniqueKey(key);
60
+ this.#pacers.set(key, { key, config });
61
+ return {
62
+ key,
63
+ config,
64
+ wait: () => pacerWait(key)
65
+ };
66
+ }
7
67
  /**
8
68
  * Register a sync capability.
9
69
  *
@@ -17,26 +77,29 @@ class Worker {
17
77
  * const worker = new Worker();
18
78
  * export default worker;
19
79
  *
20
- * worker.sync("tasksSync", {
21
- * primaryKeyProperty: "Task ID",
80
+ * const tasks = worker.database("tasks", {
81
+ * type: "managed",
82
+ * initialTitle: "Tasks",
22
83
  * schema: {
23
- * defaultName: "Tasks",
24
84
  * properties: {
25
85
  * "Task Name": Schema.title(),
26
- * "Task ID": Schema.richText(),
27
86
  * Status: Schema.select([
28
87
  * { name: "Open", color: "default" },
29
88
  * { name: "Done", color: "green" },
30
89
  * ]),
31
90
  * },
32
91
  * },
92
+ * });
93
+ *
94
+ * worker.sync("tasksSync", {
95
+ * database: tasks,
33
96
  * execute: async () => {
34
97
  * const changes = [
35
98
  * {
36
99
  * key: "task-1",
100
+ * type: "upsert",
37
101
  * properties: {
38
102
  * "Task Name": Builder.title("Write docs"),
39
- * "Task ID": Builder.richText("task-1"),
40
103
  * Status: Builder.select("Open"),
41
104
  * },
42
105
  * },
@@ -53,7 +116,74 @@ class Worker {
53
116
  */
54
117
  sync(key, config) {
55
118
  this.#validateUniqueKey(key);
56
- const capability = createSyncCapability(key, config);
119
+ const capability = createSyncCapability(
120
+ key,
121
+ config,
122
+ Array.from(this.#pacers.values())
123
+ );
124
+ this.#capabilities.set(key, capability);
125
+ return capability;
126
+ }
127
+ /**
128
+ * Register an AI connector capability.
129
+ *
130
+ * Example:
131
+ *
132
+ * ```ts
133
+ * const worker = new Worker();
134
+ * export default worker;
135
+ *
136
+ * worker.aiConnector("supportChats", {
137
+ * aiConnectorId: "connector-record-id",
138
+ * archetype: "chat",
139
+ * mode: "incremental",
140
+ * schedule: "15m",
141
+ * execute: async (state) => ({
142
+ * changes: [
143
+ * {
144
+ * type: "upsert",
145
+ * key: "thread-1",
146
+ * record: {
147
+ * createdAt: "2026-01-01T00:00:00Z",
148
+ * updatedAt: "2026-01-01T00:00:00Z",
149
+ * channel: {
150
+ * id: "channel-1",
151
+ * name: "Support",
152
+ * },
153
+ * threadId: "thread-1",
154
+ * messages: [
155
+ * {
156
+ * id: "message-1",
157
+ * content: "Hello from support",
158
+ * timestamp: "2026-01-01T00:00:00Z",
159
+ * author: {
160
+ * id: "user-1",
161
+ * username: "alice",
162
+ * },
163
+ * },
164
+ * ],
165
+ * },
166
+ * },
167
+ * ],
168
+ * hasMore: false,
169
+ * }),
170
+ * });
171
+ * ```
172
+ *
173
+ * `aiConnectorId` must be the Notion record ID of an existing custom
174
+ * connector in the workspace where you deploy this worker.
175
+ *
176
+ * @param key - The unique key for this capability.
177
+ * @param config - The AI connector configuration.
178
+ * @returns The capability object.
179
+ */
180
+ aiConnector(key, config) {
181
+ this.#validateUniqueKey(key);
182
+ const capability = createAiConnectorCapability(
183
+ key,
184
+ config,
185
+ Array.from(this.#pacers.values())
186
+ );
57
187
  this.#capabilities.set(key, capability);
58
188
  return capability;
59
189
  }
@@ -123,6 +253,40 @@ class Worker {
123
253
  this.#capabilities.set(key, capability);
124
254
  return capability;
125
255
  }
256
+ /**
257
+ * Register a webhook capability.
258
+ *
259
+ * Webhooks expose an HTTP endpoint that external services can call.
260
+ * When hit, the request is processed by the worker's execute function.
261
+ *
262
+ * Example:
263
+ *
264
+ * ```ts
265
+ * const worker = new Worker();
266
+ * export default worker;
267
+ *
268
+ * worker.webhook("onGithubPush", {
269
+ * title: "GitHub Push Webhook",
270
+ * description: "Handles push events from GitHub",
271
+ * execute: async (events, { notion }) => {
272
+ * for (const event of events) {
273
+ * console.log("Received webhook:", event.body);
274
+ * console.log("Headers:", event.headers);
275
+ * }
276
+ * },
277
+ * })
278
+ * ```
279
+ *
280
+ * @param key - The unique key for this capability. Used as the webhook name in the URL.
281
+ * @param config - The webhook configuration.
282
+ * @returns The capability object.
283
+ */
284
+ webhook(key, config) {
285
+ this.#validateUniqueKey(key);
286
+ const capability = createWebhookCapability(key, config);
287
+ this.#capabilities.set(key, capability);
288
+ return capability;
289
+ }
126
290
  /**
127
291
  * Register an OAuth capability.
128
292
  *
@@ -180,6 +344,14 @@ class Worker {
180
344
  config: c.config
181
345
  }));
182
346
  }
347
+ get manifest() {
348
+ return {
349
+ sdkVersion: SDK_VERSION,
350
+ databases: Array.from(this.#databases.values()),
351
+ pacers: Array.from(this.#pacers.values()),
352
+ capabilities: this.capabilities
353
+ };
354
+ }
183
355
  /**
184
356
  * Execute a capability by key.
185
357
  *
@@ -198,17 +370,21 @@ class Worker {
198
370
  `Cannot run OAuth capability "${key}" - OAuth capabilities only provide configuration`
199
371
  );
200
372
  }
373
+ if (!capability.handler) {
374
+ throw new Error(`Capability "${key}" cannot be executed`);
375
+ }
201
376
  return capability.handler(context, options);
202
377
  }
203
378
  #validateUniqueKey(key) {
204
379
  if (!key || typeof key !== "string") {
205
380
  throw new Error("Capability key must be a non-empty string");
206
381
  }
207
- if (this.#capabilities.has(key)) {
208
- throw new Error(`Capability with key "${key}" already registered`);
382
+ if (this.#capabilities.has(key) || this.#databases.has(key) || this.#pacers.has(key)) {
383
+ throw new Error(`Worker item with key "${key}" already registered`);
209
384
  }
210
385
  }
211
386
  }
212
387
  export {
388
+ WebhookVerificationError,
213
389
  Worker
214
390
  };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.test.d.ts","sourceRoot":"","sources":["../src/worker.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/workers",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "An SDK for building workers for the Notion Workers platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,6 +32,10 @@
32
32
  "./types": {
33
33
  "types": "./dist/types.d.ts",
34
34
  "default": "./dist/types.js"
35
+ },
36
+ "./pacer": {
37
+ "types": "./dist/pacer.d.ts",
38
+ "default": "./dist/pacer.js"
35
39
  }
36
40
  },
37
41
  "engines": {
@@ -69,6 +73,7 @@
69
73
  "@notionhq/client": "^2.2.15"
70
74
  },
71
75
  "dependencies": {
72
- "ajv": "^8.17.1"
76
+ "ajv": "^8.17.1",
77
+ "ajv-formats": "^3.0.1"
73
78
  }
74
79
  }
@@ -0,0 +1,7 @@
1
+ // ajv-formats is CJS-only and doesn't ship types compatible with
2
+ // moduleResolution: "nodenext". This declaration provides the correct
3
+ // callable default export signature so we can import it without suppression.
4
+ declare module "ajv-formats" {
5
+ import type { Ajv } from "ajv";
6
+ export default function addFormats(ajv: Ajv): Ajv;
7
+ }