@notionhq/workers 0.5.0 → 0.7.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/ajv-formats.d.js +0 -0
- 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/block.d.ts.map +1 -1
- 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/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 +2 -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.map +1 -1
- package/dist/worker.js +1 -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/block.ts +1 -5
- 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/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 +2 -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.ts +8 -34
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) {
|
|
@@ -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
|
});
|
package/src/capabilities/sync.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { ExecutionError, RateLimitError } from "../error.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
initPacerState,
|
|
5
|
-
type PacerDeclaration,
|
|
6
|
-
} from "../pacer_internal.js";
|
|
7
|
-
import type {
|
|
8
|
-
PropertyConfiguration,
|
|
9
|
-
PropertySchema,
|
|
10
|
-
Schema,
|
|
11
|
-
} from "../schema.js";
|
|
2
|
+
import { getPacerState, initPacerState, type PacerDeclaration } from "../pacer_internal.js";
|
|
3
|
+
import type { PropertyConfiguration, PropertySchema, Schema } from "../schema.js";
|
|
12
4
|
import type {
|
|
13
5
|
Cover,
|
|
14
6
|
HandlerOptions,
|
|
@@ -62,10 +54,7 @@ export type SyncMode = StatefulCapabilityMode;
|
|
|
62
54
|
/**
|
|
63
55
|
* A change representing a record to be created or updated.
|
|
64
56
|
*/
|
|
65
|
-
export type SyncChangeUpsert<
|
|
66
|
-
PK extends string,
|
|
67
|
-
S extends PropertySchema<PK>,
|
|
68
|
-
> = {
|
|
57
|
+
export type SyncChangeUpsert<PK extends string, S extends PropertySchema<PK>> = {
|
|
69
58
|
/**
|
|
70
59
|
* The type of change. Use `"upsert"` to create or update a record.
|
|
71
60
|
*/
|
|
@@ -168,11 +157,7 @@ export type SyncExecutionResult<PK extends string, State = unknown> = {
|
|
|
168
157
|
/**
|
|
169
158
|
* Configuration for a sync capability that syncs data to a database.
|
|
170
159
|
*/
|
|
171
|
-
export type SyncConfiguration<
|
|
172
|
-
PK extends string,
|
|
173
|
-
S extends Schema<PK>,
|
|
174
|
-
State = unknown,
|
|
175
|
-
> = {
|
|
160
|
+
export type SyncConfiguration<PK extends string, S extends Schema<PK>, State = unknown> = {
|
|
176
161
|
/**
|
|
177
162
|
* The database to sync data into.
|
|
178
163
|
*/
|
|
@@ -233,11 +218,7 @@ export type SyncCapability = ReturnType<typeof createSyncCapability>;
|
|
|
233
218
|
* @returns A handler function that executes the sync function, and passes data
|
|
234
219
|
* needed to complete the sync back to the platform.
|
|
235
220
|
*/
|
|
236
|
-
export function createSyncCapability<
|
|
237
|
-
PK extends string,
|
|
238
|
-
S extends Schema<PK>,
|
|
239
|
-
Context = unknown,
|
|
240
|
-
>(
|
|
221
|
+
export function createSyncCapability<PK extends string, S extends Schema<PK>, Context = unknown>(
|
|
241
222
|
key: string,
|
|
242
223
|
syncConfiguration: SyncConfiguration<PK, S, Context>,
|
|
243
224
|
pacerDeclarations?: readonly PacerDeclaration[],
|
|
@@ -249,14 +230,9 @@ export function createSyncCapability<
|
|
|
249
230
|
databaseKey: syncConfiguration.database.key,
|
|
250
231
|
primaryKeyProperty: syncConfiguration.database.config.primaryKeyProperty,
|
|
251
232
|
mode: syncConfiguration.mode,
|
|
252
|
-
schedule: syncConfiguration.schedule
|
|
253
|
-
? parseSchedule(syncConfiguration.schedule)
|
|
254
|
-
: undefined,
|
|
233
|
+
schedule: syncConfiguration.schedule ? parseSchedule(syncConfiguration.schedule) : undefined,
|
|
255
234
|
},
|
|
256
|
-
async handler(
|
|
257
|
-
runtimeContext?: StatefulRuntimeContext<Context>,
|
|
258
|
-
options?: HandlerOptions,
|
|
259
|
-
) {
|
|
235
|
+
async handler(runtimeContext?: StatefulRuntimeContext<Context>, options?: HandlerOptions) {
|
|
260
236
|
const capabilityContext = createCapabilityContext("sync");
|
|
261
237
|
const state = runtimeContext?.state ?? runtimeContext?.userContext;
|
|
262
238
|
|
|
@@ -264,10 +240,7 @@ export function createSyncCapability<
|
|
|
264
240
|
|
|
265
241
|
let executionResult: SyncExecutionResult<PK, Context>;
|
|
266
242
|
try {
|
|
267
|
-
executionResult = await syncConfiguration.execute(
|
|
268
|
-
state,
|
|
269
|
-
capabilityContext,
|
|
270
|
-
);
|
|
243
|
+
executionResult = await syncConfiguration.execute(state, capabilityContext);
|
|
271
244
|
} catch (err) {
|
|
272
245
|
if (err instanceof RateLimitError) {
|
|
273
246
|
if (!options?.concreteOutput) {
|
|
@@ -277,9 +250,7 @@ export function createSyncCapability<
|
|
|
277
250
|
_tag: "rate_limit",
|
|
278
251
|
name: err.name,
|
|
279
252
|
message: err.message,
|
|
280
|
-
...(err.retryAfter !== undefined
|
|
281
|
-
? { retryAfter: err.retryAfter }
|
|
282
|
-
: {}),
|
|
253
|
+
...(err.retryAfter !== undefined ? { retryAfter: err.retryAfter } : {}),
|
|
283
254
|
},
|
|
284
255
|
};
|
|
285
256
|
writeOutput(envelope);
|
|
@@ -304,8 +275,7 @@ export function createSyncCapability<
|
|
|
304
275
|
|
|
305
276
|
const changes = executionResult.changes.map((change) => ({
|
|
306
277
|
...change,
|
|
307
|
-
targetDatabaseKey:
|
|
308
|
-
change.targetDatabaseKey ?? syncConfiguration.database.key,
|
|
278
|
+
targetDatabaseKey: change.targetDatabaseKey ?? syncConfiguration.database.key,
|
|
309
279
|
}));
|
|
310
280
|
|
|
311
281
|
const result = {
|