@notionhq/workers 0.5.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.
- package/dist/alpha/builder.d.ts +149 -0
- package/dist/alpha/builder.d.ts.map +1 -0
- package/dist/alpha/builder.js +260 -0
- package/dist/alpha/builder.test.d.ts +2 -0
- package/dist/alpha/builder.test.d.ts.map +1 -0
- package/dist/alpha/cli/build.d.ts +13 -0
- package/dist/alpha/cli/build.d.ts.map +1 -0
- package/dist/alpha/cli/build.js +36 -0
- package/dist/alpha/cli/build.test.d.ts +2 -0
- package/dist/alpha/cli/build.test.d.ts.map +1 -0
- package/dist/alpha/cli/codegen.d.ts +10 -0
- package/dist/alpha/cli/codegen.d.ts.map +1 -0
- package/dist/alpha/cli/codegen.js +41 -0
- package/dist/alpha/cli/codegen.test.d.ts +2 -0
- package/dist/alpha/cli/codegen.test.d.ts.map +1 -0
- package/dist/alpha/cli/discover.d.ts +35 -0
- package/dist/alpha/cli/discover.d.ts.map +1 -0
- package/dist/alpha/cli/discover.js +39 -0
- package/dist/alpha/cli/discover.test.d.ts +2 -0
- package/dist/alpha/cli/discover.test.d.ts.map +1 -0
- package/dist/alpha/cli/emit-manifest.d.ts +33 -0
- package/dist/alpha/cli/emit-manifest.d.ts.map +1 -0
- package/dist/alpha/cli/emit-manifest.js +266 -0
- package/dist/alpha/cli/emit-manifest.test.d.ts +2 -0
- package/dist/alpha/cli/emit-manifest.test.d.ts.map +1 -0
- package/dist/alpha/cli/index.d.ts +3 -0
- package/dist/alpha/cli/index.d.ts.map +1 -0
- package/dist/alpha/cli/index.js +36 -0
- package/dist/alpha/context.d.ts +8 -0
- package/dist/alpha/context.d.ts.map +1 -0
- package/dist/alpha/context.js +33 -0
- package/dist/alpha/database.d.ts +90 -0
- package/dist/alpha/database.d.ts.map +1 -0
- package/dist/alpha/database.js +9 -0
- package/dist/alpha/error.d.ts +41 -0
- package/dist/alpha/error.d.ts.map +1 -0
- package/dist/alpha/error.js +25 -0
- package/dist/alpha/icon-names.d.ts +6 -0
- package/dist/alpha/icon-names.d.ts.map +1 -0
- package/dist/alpha/icon-names.js +0 -0
- package/dist/alpha/json-schema.d.ts +117 -0
- package/dist/alpha/json-schema.d.ts.map +1 -0
- package/dist/alpha/json-schema.js +0 -0
- package/dist/alpha/manifest.d.ts +44 -0
- package/dist/alpha/manifest.d.ts.map +1 -0
- package/dist/alpha/manifest.js +0 -0
- package/dist/alpha/output.d.ts +7 -0
- package/dist/alpha/output.d.ts.map +1 -0
- package/dist/alpha/output.js +8 -0
- package/dist/alpha/pacer.d.ts +74 -0
- package/dist/alpha/pacer.d.ts.map +1 -0
- package/dist/alpha/pacer.js +66 -0
- package/dist/alpha/pacer.test.d.ts +2 -0
- package/dist/alpha/pacer.test.d.ts.map +1 -0
- package/dist/alpha/schedule.d.ts +6 -0
- package/dist/alpha/schedule.d.ts.map +1 -0
- package/dist/alpha/schedule.js +43 -0
- package/dist/alpha/schedule.test.d.ts +2 -0
- package/dist/alpha/schedule.test.d.ts.map +1 -0
- package/dist/alpha/schema-builder.d.ts +79 -0
- package/dist/alpha/schema-builder.d.ts.map +1 -0
- package/dist/alpha/schema-builder.js +135 -0
- package/dist/alpha/schema.d.ts +185 -0
- package/dist/alpha/schema.d.ts.map +1 -0
- package/dist/alpha/schema.js +115 -0
- package/dist/alpha/sync.d.ts +233 -0
- package/dist/alpha/sync.d.ts.map +1 -0
- package/dist/alpha/sync.js +70 -0
- package/dist/alpha/sync.test.d.ts +2 -0
- package/dist/alpha/sync.test.d.ts.map +1 -0
- package/dist/alpha/tool.d.ts +132 -0
- package/dist/alpha/tool.d.ts.map +1 -0
- package/dist/alpha/tool.js +156 -0
- package/dist/alpha/tool.test.d.ts +2 -0
- package/dist/alpha/tool.test.d.ts.map +1 -0
- package/dist/alpha/triggers.d.ts +365 -0
- package/dist/alpha/triggers.d.ts.map +1 -0
- package/dist/alpha/triggers.generated.d.ts +246 -0
- package/dist/alpha/triggers.generated.d.ts.map +1 -0
- package/dist/alpha/triggers.generated.js +239 -0
- package/dist/alpha/triggers.js +0 -0
- package/dist/alpha/types.d.ts +228 -0
- package/dist/alpha/types.d.ts.map +1 -0
- package/dist/alpha/types.js +0 -0
- package/dist/alpha/workflow.d.ts +70 -0
- package/dist/alpha/workflow.d.ts.map +1 -0
- package/dist/alpha/workflow.js +39 -0
- package/dist/alpha/workflow.test.d.ts +2 -0
- package/dist/alpha/workflow.test.d.ts.map +1 -0
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -6
- package/dist/capabilities/ai_connector.d.ts.map +1 -1
- package/dist/capabilities/automation.d.ts.map +1 -1
- package/dist/capabilities/context.d.ts.map +1 -1
- package/dist/capabilities/custom-block.d.ts +124 -0
- package/dist/capabilities/custom-block.d.ts.map +1 -0
- package/dist/capabilities/custom-block.js +22 -0
- package/dist/capabilities/oauth.d.ts.map +1 -1
- package/dist/capabilities/output.d.ts.map +1 -1
- package/dist/capabilities/output.js +2 -4
- package/dist/capabilities/stateful-capability.d.ts.map +1 -1
- package/dist/capabilities/stateful-capability.js +2 -6
- package/dist/capabilities/sync.d.ts.map +1 -1
- package/dist/capabilities/sync.js +2 -8
- package/dist/capabilities/tool.d.ts.map +1 -1
- package/dist/capabilities/tool.js +6 -20
- package/dist/capabilities/webhook.d.ts.map +1 -1
- package/dist/capabilities/workflow.d.ts +2 -2
- package/dist/capabilities/workflow.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/schema-builder.d.ts.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +41 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +51 -4
- package/package.json +74 -14
- package/src/alpha/ajv-formats.d.ts +7 -0
- package/src/alpha/builder.test.ts +197 -0
- package/src/alpha/builder.ts +338 -0
- package/src/alpha/cli/build.test.ts +240 -0
- package/src/alpha/cli/build.ts +57 -0
- package/src/alpha/cli/codegen.test.ts +31 -0
- package/src/alpha/cli/codegen.ts +51 -0
- package/src/alpha/cli/discover.test.ts +43 -0
- package/src/alpha/cli/discover.ts +81 -0
- package/src/alpha/cli/emit-manifest.test.ts +45 -0
- package/src/alpha/cli/emit-manifest.ts +409 -0
- package/src/alpha/cli/index.ts +41 -0
- package/src/alpha/context.ts +61 -0
- package/src/alpha/database.ts +102 -0
- package/src/alpha/error.ts +49 -0
- package/src/alpha/icon-names.ts +890 -0
- package/src/alpha/json-schema.ts +180 -0
- package/src/alpha/manifest.ts +47 -0
- package/src/alpha/output.ts +8 -0
- package/src/alpha/pacer.test.ts +81 -0
- package/src/alpha/pacer.ts +181 -0
- package/src/alpha/schedule.test.ts +31 -0
- package/src/alpha/schedule.ts +53 -0
- package/src/alpha/schema-builder.ts +193 -0
- package/src/alpha/schema.ts +222 -0
- package/src/alpha/sync.test.ts +191 -0
- package/src/alpha/sync.ts +340 -0
- package/src/alpha/tool.test.ts +116 -0
- package/src/alpha/tool.ts +319 -0
- package/src/alpha/triggers.generated.ts +489 -0
- package/src/alpha/triggers.ts +500 -0
- package/src/alpha/types.ts +284 -0
- package/src/alpha/workflow.test.ts +84 -0
- package/src/alpha/workflow.ts +131 -0
- package/src/builder.test.ts +28 -60
- package/src/builder.ts +3 -10
- package/src/capabilities/ai_connector.test.ts +9 -32
- package/src/capabilities/ai_connector.ts +5 -17
- package/src/capabilities/automation.test.ts +3 -12
- package/src/capabilities/automation.ts +3 -11
- package/src/capabilities/context.ts +3 -6
- package/src/capabilities/custom-block.ts +181 -0
- package/src/capabilities/oauth.test.ts +1 -0
- package/src/capabilities/oauth.ts +1 -3
- package/src/capabilities/output.ts +1 -3
- package/src/capabilities/stateful-capability.test.ts +1 -0
- package/src/capabilities/stateful-capability.ts +2 -6
- package/src/capabilities/sync.test.ts +15 -45
- package/src/capabilities/sync.ts +10 -40
- package/src/capabilities/tool.test.ts +106 -146
- package/src/capabilities/tool.ts +17 -39
- package/src/capabilities/webhook.ts +3 -10
- package/src/capabilities/workflow.test.ts +10 -31
- package/src/capabilities/workflow.ts +5 -12
- package/src/index.ts +9 -12
- package/src/json-schema.test.ts +2 -4
- package/src/json-schema.ts +7 -6
- package/src/pacer.test.ts +1 -3
- package/src/pacer_internal.ts +1 -5
- package/src/schema-builder.test.ts +10 -35
- package/src/schema-builder.ts +5 -16
- package/src/schema.ts +2 -10
- package/src/types.ts +1 -7
- package/src/worker.test.ts +147 -0
- package/src/worker.ts +67 -35
- package/dist/block.d.ts +0 -321
- package/dist/block.d.ts.map +0 -1
- package/src/block.ts +0 -529
- /package/dist/{block.js → alpha/ajv-formats.d.js} +0 -0
package/src/builder.ts
CHANGED
|
@@ -234,9 +234,7 @@ export function relation(primaryKey: string): RelationReference {
|
|
|
234
234
|
*/
|
|
235
235
|
function validateDateString(dateString: string): void {
|
|
236
236
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
|
|
237
|
-
throw new Error(
|
|
238
|
-
`Invalid date format: ${dateString}. Expected YYYY-MM-DD format.`,
|
|
239
|
-
);
|
|
237
|
+
throw new Error(`Invalid date format: ${dateString}. Expected YYYY-MM-DD format.`);
|
|
240
238
|
}
|
|
241
239
|
|
|
242
240
|
const date = new Date(dateString);
|
|
@@ -290,10 +288,7 @@ export function emojiIcon(emoji: string): Icon {
|
|
|
290
288
|
* @param icon - The name of the Notion icon (e.g., "checkmark", "pizza", "rocket")
|
|
291
289
|
* @param color - The color variant (defaults to "gray")
|
|
292
290
|
*/
|
|
293
|
-
export function notionIcon(
|
|
294
|
-
icon: NoticonName,
|
|
295
|
-
color: NoticonColor = "gray",
|
|
296
|
-
): Icon {
|
|
291
|
+
export function notionIcon(icon: NoticonName, color: NoticonColor = "gray"): Icon {
|
|
297
292
|
return {
|
|
298
293
|
type: "notion",
|
|
299
294
|
icon,
|
|
@@ -319,9 +314,7 @@ export function imageIcon(url: string): Icon {
|
|
|
319
314
|
*/
|
|
320
315
|
export function imageCover(url: string, position = 0.5): Cover {
|
|
321
316
|
if (!Number.isFinite(position) || position < 0 || position > 1) {
|
|
322
|
-
throw new Error(
|
|
323
|
-
`Invalid cover position: ${position}. Expected a number between 0 and 1.`,
|
|
324
|
-
);
|
|
317
|
+
throw new Error(`Invalid cover position: ${position}. Expected a number between 0 and 1.`);
|
|
325
318
|
}
|
|
326
319
|
|
|
327
320
|
return {
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 = {
|
|
@@ -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
|
+
}
|
|
@@ -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
|
}
|
|
@@ -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 };
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
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 * as Builder from "../builder.js";
|
|
11
4
|
import { ExecutionError, RateLimitError } from "../error.js";
|
|
12
5
|
import { getPacerState } from "../pacer_internal.js";
|
|
@@ -18,9 +11,7 @@ describe("Worker.sync", () => {
|
|
|
18
11
|
let stdoutSpy: Mock<typeof process.stdout.write>;
|
|
19
12
|
|
|
20
13
|
beforeEach(() => {
|
|
21
|
-
stdoutSpy = vi
|
|
22
|
-
.spyOn(process.stdout, "write")
|
|
23
|
-
.mockImplementation(() => true);
|
|
14
|
+
stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
|
|
24
15
|
});
|
|
25
16
|
|
|
26
17
|
afterEach(() => {
|
|
@@ -47,10 +38,7 @@ describe("Worker.sync", () => {
|
|
|
47
38
|
});
|
|
48
39
|
|
|
49
40
|
it("can be used to build relation arrays", () => {
|
|
50
|
-
const value = [
|
|
51
|
-
Builder.relation("project-123"),
|
|
52
|
-
Builder.relation("project-456"),
|
|
53
|
-
];
|
|
41
|
+
const value = [Builder.relation("project-123"), Builder.relation("project-456")];
|
|
54
42
|
|
|
55
43
|
expect(value).toEqual([
|
|
56
44
|
{ type: "primaryKey", value: "project-123" },
|
|
@@ -81,9 +69,9 @@ describe("Worker.sync", () => {
|
|
|
81
69
|
});
|
|
82
70
|
|
|
83
71
|
it("rejects cover positions outside the supported range", () => {
|
|
84
|
-
expect(() =>
|
|
85
|
-
|
|
86
|
-
)
|
|
72
|
+
expect(() => Builder.imageCover("https://example.com/cover.jpg", 1.5)).toThrow(
|
|
73
|
+
"Expected a number between 0 and 1",
|
|
74
|
+
);
|
|
87
75
|
});
|
|
88
76
|
});
|
|
89
77
|
|
|
@@ -119,10 +107,7 @@ describe("Worker.sync", () => {
|
|
|
119
107
|
key: "task-2",
|
|
120
108
|
properties: {
|
|
121
109
|
"Task ID": Builder.title("TASK-002"),
|
|
122
|
-
Project: [
|
|
123
|
-
Builder.relation("project-123"),
|
|
124
|
-
Builder.relation("project-456"),
|
|
125
|
-
],
|
|
110
|
+
Project: [Builder.relation("project-123"), Builder.relation("project-456")],
|
|
126
111
|
},
|
|
127
112
|
},
|
|
128
113
|
],
|
|
@@ -307,12 +292,8 @@ describe("Worker.sync", () => {
|
|
|
307
292
|
|
|
308
293
|
await expect(capability.handler()).rejects.toThrow(ExecutionError);
|
|
309
294
|
|
|
310
|
-
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
311
|
-
|
|
312
|
-
);
|
|
313
|
-
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
314
|
-
expect.stringContaining(`"name":"ExecutionError"`),
|
|
315
|
-
);
|
|
295
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"_tag":"error"`));
|
|
296
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"name":"ExecutionError"`));
|
|
316
297
|
});
|
|
317
298
|
|
|
318
299
|
it("wraps RateLimitError in error envelope with _tag rate_limit", async () => {
|
|
@@ -337,12 +318,8 @@ describe("Worker.sync", () => {
|
|
|
337
318
|
|
|
338
319
|
await expect(capability.handler()).rejects.toThrow(RateLimitError);
|
|
339
320
|
|
|
340
|
-
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
341
|
-
|
|
342
|
-
);
|
|
343
|
-
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
344
|
-
expect.stringContaining(`"name":"RateLimitError"`),
|
|
345
|
-
);
|
|
321
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"_tag":"rate_limit"`));
|
|
322
|
+
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining(`"name":"RateLimitError"`));
|
|
346
323
|
});
|
|
347
324
|
|
|
348
325
|
it("includes retryAfter in rate_limit error envelope when provided", async () => {
|
|
@@ -371,18 +348,14 @@ describe("Worker.sync", () => {
|
|
|
371
348
|
.map((call) => String(call[0]))
|
|
372
349
|
.find((s) => s.includes(`"_tag":"rate_limit"`)) as string;
|
|
373
350
|
const parsed = JSON.parse(
|
|
374
|
-
output.replace(
|
|
375
|
-
/\n<__notion_output__>(.*)<\/__notion_output__>\n/,
|
|
376
|
-
"$1",
|
|
377
|
-
),
|
|
351
|
+
output.replace(/\n<__notion_output__>(.*)<\/__notion_output__>\n/, "$1"),
|
|
378
352
|
);
|
|
379
353
|
expect(parsed).toEqual({
|
|
380
354
|
_tag: "error",
|
|
381
355
|
error: {
|
|
382
356
|
_tag: "rate_limit",
|
|
383
357
|
name: "RateLimitError",
|
|
384
|
-
message:
|
|
385
|
-
"Error during worker execution: Rate limited by external API",
|
|
358
|
+
message: "Error during worker execution: Rate limited by external API",
|
|
386
359
|
retryAfter: 30,
|
|
387
360
|
},
|
|
388
361
|
});
|
|
@@ -414,10 +387,7 @@ describe("Worker.sync", () => {
|
|
|
414
387
|
.map((call) => String(call[0]))
|
|
415
388
|
.find((s) => s.includes(`"_tag":"rate_limit"`)) as string;
|
|
416
389
|
const parsed = JSON.parse(
|
|
417
|
-
output.replace(
|
|
418
|
-
/\n<__notion_output__>(.*)<\/__notion_output__>\n/,
|
|
419
|
-
"$1",
|
|
420
|
-
),
|
|
390
|
+
output.replace(/\n<__notion_output__>(.*)<\/__notion_output__>\n/, "$1"),
|
|
421
391
|
);
|
|
422
392
|
expect(parsed.error.retryAfter).toBeUndefined();
|
|
423
393
|
});
|