@notionhq/workers 0.4.0 → 0.6.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 (204) hide show
  1. package/dist/alpha/builder.d.ts +149 -0
  2. package/dist/alpha/builder.d.ts.map +1 -0
  3. package/dist/alpha/builder.js +260 -0
  4. package/dist/alpha/builder.test.d.ts +2 -0
  5. package/dist/alpha/builder.test.d.ts.map +1 -0
  6. package/dist/alpha/cli/build.d.ts +13 -0
  7. package/dist/alpha/cli/build.d.ts.map +1 -0
  8. package/dist/alpha/cli/build.js +36 -0
  9. package/dist/alpha/cli/build.test.d.ts +2 -0
  10. package/dist/alpha/cli/build.test.d.ts.map +1 -0
  11. package/dist/alpha/cli/codegen.d.ts +10 -0
  12. package/dist/alpha/cli/codegen.d.ts.map +1 -0
  13. package/dist/alpha/cli/codegen.js +41 -0
  14. package/dist/alpha/cli/codegen.test.d.ts +2 -0
  15. package/dist/alpha/cli/codegen.test.d.ts.map +1 -0
  16. package/dist/alpha/cli/discover.d.ts +35 -0
  17. package/dist/alpha/cli/discover.d.ts.map +1 -0
  18. package/dist/alpha/cli/discover.js +39 -0
  19. package/dist/alpha/cli/discover.test.d.ts +2 -0
  20. package/dist/alpha/cli/discover.test.d.ts.map +1 -0
  21. package/dist/alpha/cli/emit-manifest.d.ts +33 -0
  22. package/dist/alpha/cli/emit-manifest.d.ts.map +1 -0
  23. package/dist/alpha/cli/emit-manifest.js +266 -0
  24. package/dist/alpha/cli/emit-manifest.test.d.ts +2 -0
  25. package/dist/alpha/cli/emit-manifest.test.d.ts.map +1 -0
  26. package/dist/alpha/cli/index.d.ts +3 -0
  27. package/dist/alpha/cli/index.d.ts.map +1 -0
  28. package/dist/alpha/cli/index.js +36 -0
  29. package/dist/alpha/context.d.ts +8 -0
  30. package/dist/alpha/context.d.ts.map +1 -0
  31. package/dist/alpha/context.js +33 -0
  32. package/dist/alpha/database.d.ts +90 -0
  33. package/dist/alpha/database.d.ts.map +1 -0
  34. package/dist/alpha/database.js +9 -0
  35. package/dist/alpha/error.d.ts +41 -0
  36. package/dist/alpha/error.d.ts.map +1 -0
  37. package/dist/alpha/error.js +25 -0
  38. package/dist/alpha/icon-names.d.ts +6 -0
  39. package/dist/alpha/icon-names.d.ts.map +1 -0
  40. package/dist/alpha/icon-names.js +0 -0
  41. package/dist/alpha/json-schema.d.ts +117 -0
  42. package/dist/alpha/json-schema.d.ts.map +1 -0
  43. package/dist/alpha/json-schema.js +0 -0
  44. package/dist/alpha/manifest.d.ts +44 -0
  45. package/dist/alpha/manifest.d.ts.map +1 -0
  46. package/dist/alpha/manifest.js +0 -0
  47. package/dist/alpha/output.d.ts +7 -0
  48. package/dist/alpha/output.d.ts.map +1 -0
  49. package/dist/alpha/output.js +8 -0
  50. package/dist/alpha/pacer.d.ts +74 -0
  51. package/dist/alpha/pacer.d.ts.map +1 -0
  52. package/dist/alpha/pacer.js +66 -0
  53. package/dist/alpha/pacer.test.d.ts +2 -0
  54. package/dist/alpha/pacer.test.d.ts.map +1 -0
  55. package/dist/alpha/schedule.d.ts +6 -0
  56. package/dist/alpha/schedule.d.ts.map +1 -0
  57. package/dist/alpha/schedule.js +43 -0
  58. package/dist/alpha/schedule.test.d.ts +2 -0
  59. package/dist/alpha/schedule.test.d.ts.map +1 -0
  60. package/dist/alpha/schema-builder.d.ts +79 -0
  61. package/dist/alpha/schema-builder.d.ts.map +1 -0
  62. package/dist/alpha/schema-builder.js +135 -0
  63. package/dist/alpha/schema.d.ts +185 -0
  64. package/dist/alpha/schema.d.ts.map +1 -0
  65. package/dist/alpha/schema.js +115 -0
  66. package/dist/alpha/sync.d.ts +233 -0
  67. package/dist/alpha/sync.d.ts.map +1 -0
  68. package/dist/alpha/sync.js +70 -0
  69. package/dist/alpha/sync.test.d.ts +2 -0
  70. package/dist/alpha/sync.test.d.ts.map +1 -0
  71. package/dist/alpha/tool.d.ts +132 -0
  72. package/dist/alpha/tool.d.ts.map +1 -0
  73. package/dist/alpha/tool.js +156 -0
  74. package/dist/alpha/tool.test.d.ts +2 -0
  75. package/dist/alpha/tool.test.d.ts.map +1 -0
  76. package/dist/alpha/triggers.d.ts +365 -0
  77. package/dist/alpha/triggers.d.ts.map +1 -0
  78. package/dist/alpha/triggers.generated.d.ts +246 -0
  79. package/dist/alpha/triggers.generated.d.ts.map +1 -0
  80. package/dist/alpha/triggers.generated.js +239 -0
  81. package/dist/alpha/triggers.js +0 -0
  82. package/dist/alpha/types.d.ts +228 -0
  83. package/dist/alpha/types.d.ts.map +1 -0
  84. package/dist/alpha/types.js +0 -0
  85. package/dist/alpha/workflow.d.ts +70 -0
  86. package/dist/alpha/workflow.d.ts.map +1 -0
  87. package/dist/alpha/workflow.js +39 -0
  88. package/dist/alpha/workflow.test.d.ts +2 -0
  89. package/dist/alpha/workflow.test.d.ts.map +1 -0
  90. package/dist/builder.d.ts +7 -1
  91. package/dist/builder.d.ts.map +1 -1
  92. package/dist/builder.js +12 -3
  93. package/dist/capabilities/ai_connector.d.ts.map +1 -1
  94. package/dist/capabilities/automation.d.ts.map +1 -1
  95. package/dist/capabilities/context.d.ts.map +1 -1
  96. package/dist/capabilities/context.js +1 -1
  97. package/dist/capabilities/custom-block.d.ts +124 -0
  98. package/dist/capabilities/custom-block.d.ts.map +1 -0
  99. package/dist/capabilities/custom-block.js +22 -0
  100. package/dist/capabilities/oauth.d.ts.map +1 -1
  101. package/dist/capabilities/output.d.ts.map +1 -1
  102. package/dist/capabilities/output.js +2 -4
  103. package/dist/capabilities/stateful-capability.d.ts.map +1 -1
  104. package/dist/capabilities/stateful-capability.js +3 -7
  105. package/dist/capabilities/sync.d.ts +11 -1
  106. package/dist/capabilities/sync.d.ts.map +1 -1
  107. package/dist/capabilities/sync.js +2 -8
  108. package/dist/capabilities/tool.d.ts.map +1 -1
  109. package/dist/capabilities/tool.js +6 -20
  110. package/dist/capabilities/webhook.d.ts.map +1 -1
  111. package/dist/capabilities/workflow.d.ts +50 -0
  112. package/dist/capabilities/workflow.d.ts.map +1 -0
  113. package/dist/capabilities/workflow.js +40 -0
  114. package/dist/capabilities/workflow.test.d.ts +2 -0
  115. package/dist/capabilities/workflow.test.d.ts.map +1 -0
  116. package/dist/index.d.ts +5 -3
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +2 -1
  119. package/dist/json-schema.d.ts.map +1 -1
  120. package/dist/schema-builder.d.ts.map +1 -1
  121. package/dist/schema.d.ts.map +1 -1
  122. package/dist/triggers.d.ts +365 -0
  123. package/dist/triggers.d.ts.map +1 -0
  124. package/dist/triggers.generated.d.ts +246 -0
  125. package/dist/triggers.generated.d.ts.map +1 -0
  126. package/dist/triggers.generated.js +239 -0
  127. package/dist/triggers.js +0 -0
  128. package/dist/types.d.ts +18 -0
  129. package/dist/types.d.ts.map +1 -1
  130. package/dist/worker.d.ts +72 -2
  131. package/dist/worker.d.ts.map +1 -1
  132. package/dist/worker.js +85 -4
  133. package/package.json +81 -14
  134. package/src/alpha/ajv-formats.d.ts +7 -0
  135. package/src/alpha/builder.test.ts +197 -0
  136. package/src/alpha/builder.ts +338 -0
  137. package/src/alpha/cli/build.test.ts +240 -0
  138. package/src/alpha/cli/build.ts +57 -0
  139. package/src/alpha/cli/codegen.test.ts +31 -0
  140. package/src/alpha/cli/codegen.ts +51 -0
  141. package/src/alpha/cli/discover.test.ts +43 -0
  142. package/src/alpha/cli/discover.ts +81 -0
  143. package/src/alpha/cli/emit-manifest.test.ts +45 -0
  144. package/src/alpha/cli/emit-manifest.ts +409 -0
  145. package/src/alpha/cli/index.ts +41 -0
  146. package/src/alpha/context.ts +61 -0
  147. package/src/alpha/database.ts +102 -0
  148. package/src/alpha/error.ts +49 -0
  149. package/src/alpha/icon-names.ts +890 -0
  150. package/src/alpha/json-schema.ts +180 -0
  151. package/src/alpha/manifest.ts +47 -0
  152. package/src/alpha/output.ts +8 -0
  153. package/src/alpha/pacer.test.ts +81 -0
  154. package/src/alpha/pacer.ts +181 -0
  155. package/src/alpha/schedule.test.ts +31 -0
  156. package/src/alpha/schedule.ts +53 -0
  157. package/src/alpha/schema-builder.ts +193 -0
  158. package/src/alpha/schema.ts +222 -0
  159. package/src/alpha/sync.test.ts +191 -0
  160. package/src/alpha/sync.ts +340 -0
  161. package/src/alpha/tool.test.ts +116 -0
  162. package/src/alpha/tool.ts +319 -0
  163. package/src/alpha/triggers.generated.ts +489 -0
  164. package/src/alpha/triggers.ts +500 -0
  165. package/src/alpha/types.ts +284 -0
  166. package/src/alpha/workflow.test.ts +84 -0
  167. package/src/alpha/workflow.ts +131 -0
  168. package/src/builder.test.ts +28 -60
  169. package/src/builder.ts +20 -7
  170. package/src/capabilities/ai_connector.test.ts +9 -32
  171. package/src/capabilities/ai_connector.ts +5 -17
  172. package/src/capabilities/automation.test.ts +3 -12
  173. package/src/capabilities/automation.ts +3 -11
  174. package/src/capabilities/context.ts +5 -8
  175. package/src/capabilities/custom-block.ts +181 -0
  176. package/src/capabilities/oauth.test.ts +1 -0
  177. package/src/capabilities/oauth.ts +1 -3
  178. package/src/capabilities/output.ts +1 -3
  179. package/src/capabilities/stateful-capability.test.ts +1 -0
  180. package/src/capabilities/stateful-capability.ts +3 -7
  181. package/src/capabilities/sync.test.ts +76 -42
  182. package/src/capabilities/sync.ts +16 -40
  183. package/src/capabilities/tool.test.ts +106 -146
  184. package/src/capabilities/tool.ts +17 -39
  185. package/src/capabilities/webhook.ts +3 -10
  186. package/src/capabilities/workflow.test.ts +163 -0
  187. package/src/capabilities/workflow.ts +112 -0
  188. package/src/index.ts +18 -6
  189. package/src/json-schema.test.ts +2 -4
  190. package/src/json-schema.ts +7 -6
  191. package/src/pacer.test.ts +1 -3
  192. package/src/pacer_internal.ts +1 -5
  193. package/src/schema-builder.test.ts +10 -35
  194. package/src/schema-builder.ts +6 -16
  195. package/src/schema.ts +2 -10
  196. package/src/triggers.generated.ts +489 -0
  197. package/src/triggers.ts +504 -0
  198. package/src/types.ts +21 -7
  199. package/src/worker.test.ts +147 -0
  200. package/src/worker.ts +155 -32
  201. package/dist/block.d.ts +0 -321
  202. package/dist/block.d.ts.map +0 -1
  203. package/src/block.ts +0 -529
  204. /package/dist/{block.js → alpha/ajv-formats.d.js} +0 -0
package/src/builder.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { NoticonName } from "./icon-names.js";
2
2
  import type {
3
+ Cover,
3
4
  DateValue,
4
5
  Icon,
5
6
  NoticonColor,
@@ -233,9 +234,7 @@ export function relation(primaryKey: string): RelationReference {
233
234
  */
234
235
  function validateDateString(dateString: string): void {
235
236
  if (!/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
236
- throw new Error(
237
- `Invalid date format: ${dateString}. Expected YYYY-MM-DD format.`,
238
- );
237
+ throw new Error(`Invalid date format: ${dateString}. Expected YYYY-MM-DD format.`);
239
238
  }
240
239
 
241
240
  const date = new Date(dateString);
@@ -289,10 +288,7 @@ export function emojiIcon(emoji: string): Icon {
289
288
  * @param icon - The name of the Notion icon (e.g., "checkmark", "pizza", "rocket")
290
289
  * @param color - The color variant (defaults to "gray")
291
290
  */
292
- export function notionIcon(
293
- icon: NoticonName,
294
- color: NoticonColor = "gray",
295
- ): Icon {
291
+ export function notionIcon(icon: NoticonName, color: NoticonColor = "gray"): Icon {
296
292
  return {
297
293
  type: "notion",
298
294
  icon,
@@ -310,3 +306,20 @@ export function imageIcon(url: string): Icon {
310
306
  url,
311
307
  };
312
308
  }
309
+
310
+ /**
311
+ * Creates an image cover from an external URL.
312
+ * @param url - The URL of the image (e.g., "https://example.com/cover.png")
313
+ * @param position - Vertical image position, from 0 (top) to 1 (bottom). Defaults to 0.5.
314
+ */
315
+ export function imageCover(url: string, position = 0.5): Cover {
316
+ if (!Number.isFinite(position) || position < 0 || position > 1) {
317
+ throw new Error(`Invalid cover position: ${position}. Expected a number between 0 and 1.`);
318
+ }
319
+
320
+ return {
321
+ type: "image",
322
+ url,
323
+ position,
324
+ };
325
+ }
@@ -1,12 +1,5 @@
1
- import {
2
- afterEach,
3
- beforeEach,
4
- describe,
5
- expect,
6
- it,
7
- type Mock,
8
- vi,
9
- } from "vitest";
1
+ import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from "vitest";
2
+
10
3
  import { ExecutionError } from "../error.js";
11
4
  import { getPacerState } from "../pacer_internal.js";
12
5
  import { Worker } from "../worker.js";
@@ -17,9 +10,7 @@ describe("Worker.aiConnector", () => {
17
10
  let stdoutSpy: Mock<typeof process.stdout.write>;
18
11
 
19
12
  beforeEach(() => {
20
- stdoutSpy = vi
21
- .spyOn(process.stdout, "write")
22
- .mockImplementation(() => true);
13
+ stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
23
14
  });
24
15
 
25
16
  afterEach(() => {
@@ -86,12 +77,8 @@ describe("Worker.aiConnector", () => {
86
77
 
87
78
  await capability.handler();
88
79
 
89
- expect(stdoutSpy).toHaveBeenCalledWith(
90
- expect.stringContaining(`"_tag":"success"`),
91
- );
92
- expect(stdoutSpy).toHaveBeenCalledWith(
93
- expect.stringContaining(`"thread-1"`),
94
- );
80
+ expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"_tag":"success"`));
81
+ expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"thread-1"`));
95
82
  });
96
83
 
97
84
  it("passes state through from legacy runtime userContext", async () => {
@@ -106,15 +93,9 @@ describe("Worker.aiConnector", () => {
106
93
  execute,
107
94
  });
108
95
 
109
- await capability.handler(
110
- { userContext: { cursor: "cursor-1" } },
111
- { concreteOutput: true },
112
- );
96
+ await capability.handler({ userContext: { cursor: "cursor-1" } }, { concreteOutput: true });
113
97
 
114
- expect(execute).toHaveBeenCalledWith(
115
- { cursor: "cursor-1" },
116
- expect.anything(),
117
- );
98
+ expect(execute).toHaveBeenCalledWith({ cursor: "cursor-1" }, expect.anything());
118
99
  expect(stdoutSpy).not.toHaveBeenCalled();
119
100
  });
120
101
 
@@ -161,9 +142,7 @@ describe("Worker.aiConnector", () => {
161
142
  },
162
143
  },
163
144
  });
164
- expect(
165
- result.nextPacerStates.api?.lastScheduledAtMs,
166
- ).toBeGreaterThanOrEqual(before);
145
+ expect(result.nextPacerStates.api?.lastScheduledAtMs).toBeGreaterThanOrEqual(before);
167
146
  });
168
147
 
169
148
  describe("pacer local fallback", () => {
@@ -243,9 +222,7 @@ describe("Worker.aiConnector", () => {
243
222
  });
244
223
 
245
224
  await expect(capability.handler()).rejects.toThrow(ExecutionError);
246
- expect(stdoutSpy).toHaveBeenCalledWith(
247
- expect.stringContaining(`"_tag":"error"`),
248
- );
225
+ expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"_tag":"error"`));
249
226
  });
250
227
 
251
228
  it("accepts chat records at compile time", () => {
@@ -85,18 +85,14 @@ export type AiConnectorChangeUpsert<A extends AiConnectorArchetype> = {
85
85
  record: AiConnectorRecordByArchetype[A];
86
86
  };
87
87
 
88
- export type AiConnectorChange<A extends AiConnectorArchetype> =
89
- AiConnectorChangeUpsert<A>;
88
+ export type AiConnectorChange<A extends AiConnectorArchetype> = AiConnectorChangeUpsert<A>;
90
89
 
91
90
  export type AiConnectorExecutionResult<
92
91
  A extends AiConnectorArchetype,
93
92
  State = unknown,
94
93
  > = StatefulExecutionResult<AiConnectorChange<A>, State>;
95
94
 
96
- export type AiConnectorConfiguration<
97
- A extends AiConnectorArchetype,
98
- State = unknown,
99
- > = {
95
+ export type AiConnectorConfiguration<A extends AiConnectorArchetype, State = unknown> = {
100
96
  /**
101
97
  * The Notion record ID of an existing custom connector in the target workspace.
102
98
  *
@@ -113,9 +109,7 @@ export type AiConnectorConfiguration<
113
109
  ) => Promise<AiConnectorExecutionResult<A, State>>;
114
110
  };
115
111
 
116
- export type AiConnectorCapability = ReturnType<
117
- typeof createAiConnectorCapability
118
- >;
112
+ export type AiConnectorCapability = ReturnType<typeof createAiConnectorCapability>;
119
113
 
120
114
  type NormalizedAiConnectorConfiguration<A extends AiConnectorArchetype> = {
121
115
  aiConnectorId: string;
@@ -131,10 +125,7 @@ type AiConnectorHandlerResult<A extends AiConnectorArchetype, State> = {
131
125
  nextPacerStates: Record<string, PacerEntry>;
132
126
  };
133
127
 
134
- export function createAiConnectorCapability<
135
- A extends AiConnectorArchetype,
136
- State = unknown,
137
- >(
128
+ export function createAiConnectorCapability<A extends AiConnectorArchetype, State = unknown>(
138
129
  key: string,
139
130
  configuration: AiConnectorConfiguration<A, State>,
140
131
  pacerDeclarations?: readonly PacerDeclaration[],
@@ -150,10 +141,7 @@ export function createAiConnectorCapability<
150
141
  ? {}
151
142
  : { schedule: parseSchedule(configuration.schedule) }),
152
143
  } satisfies NormalizedAiConnectorConfiguration<A>,
153
- async handler(
154
- runtimeContext?: StatefulRuntimeContext<State>,
155
- options?: HandlerOptions,
156
- ) {
144
+ async handler(runtimeContext?: StatefulRuntimeContext<State>, options?: HandlerOptions) {
157
145
  const capabilityContext = createCapabilityContext("ai_connector");
158
146
  const state = runtimeContext?.state ?? runtimeContext?.userContext;
159
147
 
@@ -1,12 +1,5 @@
1
- import {
2
- afterEach,
3
- beforeEach,
4
- describe,
5
- expect,
6
- it,
7
- type Mock,
8
- vi,
9
- } from "vitest";
1
+ import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from "vitest";
2
+
10
3
  import { ExecutionError } from "../error.js";
11
4
  import type { PageObjectResponse } from "./automation.js";
12
5
  import { createAutomationCapability } from "./automation.js";
@@ -15,9 +8,7 @@ describe("createAutomationCapability", () => {
15
8
  let stdoutSpy: Mock<typeof process.stdout.write>;
16
9
 
17
10
  beforeEach(() => {
18
- stdoutSpy = vi
19
- .spyOn(process.stdout, "write")
20
- .mockImplementation(() => true);
11
+ stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
21
12
  });
22
13
 
23
14
  afterEach(() => {
@@ -64,10 +64,7 @@ export interface AutomationConfiguration {
64
64
  * @param context - The capability execution context (Notion client, etc.)
65
65
  * @returns A promise that resolves when the automation completes
66
66
  */
67
- execute: (
68
- event: AutomationEvent,
69
- context: CapabilityContext,
70
- ) => Promise<void> | void;
67
+ execute: (event: AutomationEvent, context: CapabilityContext) => Promise<void> | void;
71
68
  }
72
69
 
73
70
  /**
@@ -78,9 +75,7 @@ export interface AutomationHandlerResult {
78
75
  description: string;
79
76
  }
80
77
 
81
- export type AutomationCapability = ReturnType<
82
- typeof createAutomationCapability
83
- >;
78
+ export type AutomationCapability = ReturnType<typeof createAutomationCapability>;
84
79
 
85
80
  /**
86
81
  * Creates an automation capability from configuration.
@@ -89,10 +84,7 @@ export type AutomationCapability = ReturnType<
89
84
  * @param config - The automation configuration.
90
85
  * @returns The capability object.
91
86
  */
92
- export function createAutomationCapability(
93
- key: string,
94
- config: AutomationConfiguration,
95
- ) {
87
+ export function createAutomationCapability(key: string, config: AutomationConfiguration) {
96
88
  return {
97
89
  _tag: "automation" as const,
98
90
  key,
@@ -1,5 +1,6 @@
1
1
  import { Client } from "@notionhq/client";
2
2
  import type { ClientOptions } from "@notionhq/client/build/src/Client.js";
3
+
3
4
  import type { CapabilityType } from "../worker.js";
4
5
 
5
6
  export type CapabilityContext = {
@@ -9,8 +10,8 @@ export type CapabilityContext = {
9
10
 
10
11
  const FIX_STEPS =
11
12
  "\n\nTo fix this:\n" +
12
- "1. Create an internal integration at https://www.notion.so/profile/integrations/internal\n" +
13
- "2. Give the integration access to the relevant pages/databases\n" +
13
+ "1. Create a connection at https://app.notion.com/developers/connections\n" +
14
+ "2. Give the connection access to the relevant pages/databases\n" +
14
15
  "3. Add NOTION_API_TOKEN=<your-token> to your .env file\n" +
15
16
  "4. For deployed workers, run: ntn workers env push";
16
17
 
@@ -32,9 +33,7 @@ function missingTokenMessage(capabilityType: CapabilityType): string {
32
33
  );
33
34
  }
34
35
 
35
- function createUnauthenticatedNotionProxy(
36
- capabilityType: CapabilityType,
37
- ): Client {
36
+ function createUnauthenticatedNotionProxy(capabilityType: CapabilityType): Client {
38
37
  return new Proxy({} as Client, {
39
38
  get(_target, prop) {
40
39
  if (prop === "then" || typeof prop === "symbol") {
@@ -45,9 +44,7 @@ function createUnauthenticatedNotionProxy(
45
44
  });
46
45
  }
47
46
 
48
- export function createCapabilityContext(
49
- capabilityType: CapabilityType,
50
- ): CapabilityContext {
47
+ export function createCapabilityContext(capabilityType: CapabilityType): CapabilityContext {
51
48
  const options: ClientOptions = {};
52
49
 
53
50
  if (process.env.NOTION_API_BASE_URL) {
@@ -0,0 +1,181 @@
1
+ // ============================================================================
2
+ // Custom Block Authoring API
3
+ // ============================================================================
4
+
5
+ /**
6
+ * Icon for a custom block data source. Mirrors the server/client
7
+ * `CustomBlockManifestIcon` (`@notionhq/shared/customViews/customBlockManifestTypes`).
8
+ */
9
+ export type CustomBlockManifestIcon =
10
+ | { type: "emoji"; emoji: string }
11
+ | { type: "external"; url: string };
12
+
13
+ /**
14
+ * Public-API-shaped property type names usable in a custom block manifest.
15
+ */
16
+ export type CustomBlockManifestPropertyType =
17
+ | "title"
18
+ | "rich_text"
19
+ | "number"
20
+ | "select"
21
+ | "multi_select"
22
+ | "status"
23
+ | "date"
24
+ | "people"
25
+ | "files"
26
+ | "checkbox"
27
+ | "url"
28
+ | "email"
29
+ | "phone_number"
30
+ | "formula"
31
+ | "relation"
32
+ | "rollup"
33
+ | "created_time"
34
+ | "created_by"
35
+ | "last_edited_time"
36
+ | "last_edited_by"
37
+ | "last_visited_time"
38
+ | "button"
39
+ | "unique_id"
40
+ | "location"
41
+ | "verification"
42
+ | "place";
43
+
44
+ /**
45
+ * Describes a single property exposed by a custom block data source.
46
+ */
47
+ export type CustomBlockManifestProperty = {
48
+ name: string;
49
+ description?: string;
50
+ type: CustomBlockManifestPropertyType;
51
+ };
52
+
53
+ /**
54
+ * Rich schema describing one of a custom block's data sources.
55
+ */
56
+ export type CustomBlockManifestDataSource = {
57
+ /** Display name for the data source. */
58
+ name: string;
59
+ /** Optional human-readable description of the data source. */
60
+ description?: string;
61
+ /** Optional icon for the data source. */
62
+ icon?: CustomBlockManifestIcon;
63
+ /** Optional property schema keyed by property key. */
64
+ properties?: Record<string, CustomBlockManifestProperty>;
65
+ };
66
+
67
+ export type CustomBlockManifest = {
68
+ version: 1;
69
+ /**
70
+ * The block's datasources schema, mapping keys you name to {@link CustomBlockManifestDataSource}
71
+ *
72
+ * @example
73
+ *
74
+ * {
75
+ * "myDataSource": {
76
+ * "name": "My Data Source",
77
+ * "description": "A description of my data source",
78
+ * "icon": "icon.png",
79
+ * "properties": {
80
+ * "property1": {
81
+ * "name": "Property 1",
82
+ * "type": "string"
83
+ * }
84
+ * }
85
+ * }
86
+ * }
87
+ */
88
+ dataSources: Record<string, CustomBlockManifestDataSource>;
89
+ };
90
+
91
+ /**
92
+ * A custom block is a front-end web app served in an iframe in the client with live data access.
93
+ *
94
+ * Available `type`s are `project` (a buildable project dir) and `static` (an already-built dir served as-is).
95
+ */
96
+ export type CustomBlockConfiguration = (
97
+ | {
98
+ /** Buildable project dir (the default). */
99
+ type?: "project";
100
+ /** Path to the project dir, relative to the worker root (e.g. `"./blocks/foo"`). */
101
+ path: string;
102
+ /** Build command run in `path`. Defaults to `npm run build`. */
103
+ command?: string;
104
+ /** Built-output dir relative to `path`. Defaults to `dist`. */
105
+ output?: string;
106
+ }
107
+ | {
108
+ /** An already-built browser-bundle dir; served as-is, no build step. */
109
+ type: "static";
110
+ /** Path to the prebuilt dir, relative to the worker root. */
111
+ path: string;
112
+ command?: never;
113
+ output?: never;
114
+ }
115
+ ) &
116
+ Partial<CustomBlockManifest>;
117
+
118
+ /**
119
+ * The build source of a custom block, mirroring the server's
120
+ * `BlockSourceDeclaration`. `project` is a buildable dir (`command` defaults to
121
+ * `npm run build`, `output` to `dist`); `static` is an already-built dir served
122
+ * as-is.
123
+ */
124
+ export type BlockSourceDeclaration =
125
+ | { type: "project"; path: string; command?: string; output?: string }
126
+ | { type: "static"; path: string };
127
+
128
+ /**
129
+ * Config payload carried in the runtime manifest for a `_tag: "custom_block"`
130
+ * capability entry. The server parses this (see `RawBlockCapabilityConfig` in
131
+ * `capabilities-service.ts`): `source` is the build entry and `manifest` is the
132
+ * author-declared {@link CustomBlockManifest} describing the block's data-source
133
+ * schema. Data-source *bindings* are instance-level and are not carried here.
134
+ */
135
+ export type CustomBlockCapabilityConfig = {
136
+ source: BlockSourceDeclaration;
137
+ manifest: CustomBlockManifest;
138
+ };
139
+
140
+ /**
141
+ * A custom-block capability entry. Unlike other capabilities it has no runtime
142
+ * handler — it is a build-time/deploy-time declaration only, carried through
143
+ * the manifest so the server can build and bind the block on deploy.
144
+ */
145
+ export type CustomBlockCapability = {
146
+ readonly _tag: "custom_block";
147
+ readonly key: string;
148
+ readonly config: CustomBlockCapabilityConfig;
149
+ };
150
+
151
+ /**
152
+ * Builds a custom-block capability entry from its authoring configuration. The
153
+ * author-declared `dataSources` schema is carried verbatim into the block
154
+ * {@link CustomBlockManifest}; no bindings are emitted.
155
+ */
156
+ export function createCustomBlockCapability(
157
+ key: string,
158
+ config: CustomBlockConfiguration,
159
+ ): CustomBlockCapability {
160
+ const source: BlockSourceDeclaration =
161
+ config.type === "static"
162
+ ? { type: "static", path: config.path }
163
+ : {
164
+ type: "project",
165
+ path: config.path,
166
+ ...(config.command !== undefined ? { command: config.command } : {}),
167
+ ...(config.output !== undefined ? { output: config.output } : {}),
168
+ };
169
+
170
+ return {
171
+ _tag: "custom_block",
172
+ key,
173
+ config: {
174
+ source,
175
+ manifest: {
176
+ version: config.version ?? 1,
177
+ dataSources: config.dataSources ?? {},
178
+ },
179
+ },
180
+ };
181
+ }
@@ -1,4 +1,5 @@
1
1
  import { afterEach, describe, expect, it } from "vitest";
2
+
2
3
  import { createOAuthCapability } from "./oauth.js";
3
4
 
4
5
  describe("oauth", () => {
@@ -84,9 +84,7 @@ export interface UserManagedOAuthConfiguration {
84
84
  /**
85
85
  * Union type representing either Notion-managed or user-managed OAuth configuration.
86
86
  */
87
- export type OAuthConfiguration =
88
- | NotionManagedOAuthConfiguration
89
- | UserManagedOAuthConfiguration;
87
+ export type OAuthConfiguration = NotionManagedOAuthConfiguration | UserManagedOAuthConfiguration;
90
88
 
91
89
  export type OAuthCapability = ReturnType<typeof createOAuthCapability>;
92
90
 
@@ -2,7 +2,5 @@
2
2
  * Writes a notion_output envelope to stdout using the shared wire format.
3
3
  */
4
4
  export function writeOutput(value: unknown): void {
5
- process.stdout.write(
6
- `\n<__notion_output__>${JSON.stringify(value)}</__notion_output__>\n`,
7
- );
5
+ process.stdout.write(`\n<__notion_output__>${JSON.stringify(value)}</__notion_output__>\n`);
8
6
  }
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
+
2
3
  import { parseSchedule } from "./stateful-capability.js";
3
4
 
4
5
  describe("stateful capability shared primitives", () => {
@@ -48,7 +48,7 @@ export function parseSchedule(schedule: Schedule): SyncSchedule {
48
48
  }
49
49
 
50
50
  const match = schedule.match(/^(\d+)(m|h|d)$/);
51
- if (!match || !match[1] || !match[2]) {
51
+ if (!match?.[1] || !match[2]) {
52
52
  throw new Error(
53
53
  `Invalid schedule format: "${schedule}". Use "continuous" or an interval like "30m", "1h", "1d".`,
54
54
  );
@@ -73,14 +73,10 @@ export function parseSchedule(schedule: Schedule): SyncSchedule {
73
73
  }
74
74
 
75
75
  if (intervalMs < MIN_INTERVAL_MS) {
76
- throw new Error(
77
- `Schedule interval must be at least 1 minute. Got: "${schedule}"`,
78
- );
76
+ throw new Error(`Schedule interval must be at least 1 minute. Got: "${schedule}"`);
79
77
  }
80
78
  if (intervalMs > MAX_INTERVAL_MS) {
81
- throw new Error(
82
- `Schedule interval must be at most 7 days. Got: "${schedule}"`,
83
- );
79
+ throw new Error(`Schedule interval must be at most 7 days. Got: "${schedule}"`);
84
80
  }
85
81
 
86
82
  return { type: "interval", intervalMs };