@project-ajax/sdk 0.0.68 → 0.0.69
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/capabilities/automation.d.ts +8 -28
- package/dist/capabilities/automation.d.ts.map +1 -1
- package/dist/capabilities/automation.js +3 -2
- package/dist/capabilities/oauth.d.ts +6 -31
- package/dist/capabilities/oauth.d.ts.map +1 -1
- package/dist/capabilities/oauth.js +4 -2
- package/dist/capabilities/sync.d.ts +4 -2
- package/dist/capabilities/sync.d.ts.map +1 -1
- package/dist/capabilities/sync.js +3 -2
- package/dist/capabilities/tool.d.ts +5 -25
- package/dist/capabilities/tool.d.ts.map +1 -1
- package/dist/capabilities/tool.js +3 -2
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -9
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +175 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +218 -0
- package/package.json +1 -5
- package/src/capabilities/automation.test.ts +17 -23
- package/src/capabilities/automation.ts +14 -30
- package/src/capabilities/oauth.test.ts +16 -15
- package/src/capabilities/oauth.ts +7 -31
- package/src/capabilities/sync.ts +6 -3
- package/src/capabilities/tool.test.ts +105 -89
- package/src/capabilities/tool.ts +12 -31
- package/src/index.ts +5 -4
- package/src/types.ts +11 -0
- package/src/worker.ts +278 -0
package/dist/worker.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { createAutomationCapability } from "./capabilities/automation.js";
|
|
2
|
+
import { createOAuthCapability } from "./capabilities/oauth.js";
|
|
3
|
+
import { createSyncCapability } from "./capabilities/sync.js";
|
|
4
|
+
import { createToolCapability } from "./capabilities/tool.js";
|
|
5
|
+
class Worker {
|
|
6
|
+
#capabilities = /* @__PURE__ */ new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Register a sync capability.
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { Worker } from "@project-ajax/sdk";
|
|
14
|
+
* import * as Builder from "@project-ajax/sdk/builder";
|
|
15
|
+
* import * as Schema from "@project-ajax/sdk/schema";
|
|
16
|
+
*
|
|
17
|
+
* const worker = new Worker();
|
|
18
|
+
* export default worker;
|
|
19
|
+
*
|
|
20
|
+
* worker.sync("tasksSync", {
|
|
21
|
+
* primaryKeyProperty: "Task ID",
|
|
22
|
+
* schema: {
|
|
23
|
+
* defaultName: "Tasks",
|
|
24
|
+
* properties: {
|
|
25
|
+
* "Task Name": Schema.title(),
|
|
26
|
+
* "Task ID": Schema.richText(),
|
|
27
|
+
* Status: Schema.select([
|
|
28
|
+
* { name: "Open", color: "default" },
|
|
29
|
+
* { name: "Done", color: "green" },
|
|
30
|
+
* ]),
|
|
31
|
+
* },
|
|
32
|
+
* },
|
|
33
|
+
* execute: async () => {
|
|
34
|
+
* const objects = [
|
|
35
|
+
* {
|
|
36
|
+
* key: "task-1",
|
|
37
|
+
* properties: {
|
|
38
|
+
* "Task Name": Builder.title("Write docs"),
|
|
39
|
+
* "Task ID": Builder.richText("task-1"),
|
|
40
|
+
* Status: Builder.select("Open"),
|
|
41
|
+
* },
|
|
42
|
+
* },
|
|
43
|
+
* ];
|
|
44
|
+
*
|
|
45
|
+
* return { objects, done: true };
|
|
46
|
+
* },
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @param key - The unique key for this capability.
|
|
51
|
+
* @param config - The sync configuration.
|
|
52
|
+
* @returns The capability object.
|
|
53
|
+
*/
|
|
54
|
+
sync(key, config) {
|
|
55
|
+
this.#validateUniqueKey(key);
|
|
56
|
+
const capability = createSyncCapability(key, config);
|
|
57
|
+
this.#capabilities.set(key, capability);
|
|
58
|
+
return capability;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Register a tool capability.
|
|
62
|
+
*
|
|
63
|
+
* Example:
|
|
64
|
+
*
|
|
65
|
+
* ```ts
|
|
66
|
+
* worker.tool<{ name: string }, string>("sayHello", {
|
|
67
|
+
* title: "Say Hello",
|
|
68
|
+
* description: "Say hello to the user",
|
|
69
|
+
* schema: {
|
|
70
|
+
* type: "object",
|
|
71
|
+
* properties: {
|
|
72
|
+
* name: { type: "string" },
|
|
73
|
+
* },
|
|
74
|
+
* required: ["name"],
|
|
75
|
+
* },
|
|
76
|
+
* execute: ({ name }) => {
|
|
77
|
+
* return `Hello, ${name}!`;
|
|
78
|
+
* },
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
*
|
|
83
|
+
* @param key - The unique key for this capability.
|
|
84
|
+
* @param config - The tool configuration.
|
|
85
|
+
* @returns The capability object.
|
|
86
|
+
*/
|
|
87
|
+
tool(key, config) {
|
|
88
|
+
this.#validateUniqueKey(key);
|
|
89
|
+
const capability = createToolCapability(key, config);
|
|
90
|
+
this.#capabilities.set(key, capability);
|
|
91
|
+
return capability;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Register an automation capability.
|
|
95
|
+
*
|
|
96
|
+
* Example:
|
|
97
|
+
*
|
|
98
|
+
* ```ts
|
|
99
|
+
* const worker = new Worker();
|
|
100
|
+
* export default worker;
|
|
101
|
+
*
|
|
102
|
+
* worker.automation("sendWelcomeEmail", {
|
|
103
|
+
* title: "Send Welcome Email",
|
|
104
|
+
* description: "Sends a welcome email when a new user is added",
|
|
105
|
+
* execute: async (context) => {
|
|
106
|
+
* const { pageId, pageData } = context;
|
|
107
|
+
*
|
|
108
|
+
* // Access page properties from the Public API format
|
|
109
|
+
* if (pageData) {
|
|
110
|
+
* const name = pageData.properties.Name; // Access any property
|
|
111
|
+
* const status = pageData.properties.Status;
|
|
112
|
+
* console.log(`Processing: ${name}`);
|
|
113
|
+
* }
|
|
114
|
+
*
|
|
115
|
+
* // Your automation logic here
|
|
116
|
+
* await sendEmail(pageId);
|
|
117
|
+
* },
|
|
118
|
+
* })
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @param key - The unique key for this capability.
|
|
122
|
+
* @param config - The automation configuration.
|
|
123
|
+
* @returns The capability object.
|
|
124
|
+
*/
|
|
125
|
+
automation(key, config) {
|
|
126
|
+
this.#validateUniqueKey(key);
|
|
127
|
+
const capability = createAutomationCapability(key, config);
|
|
128
|
+
this.#capabilities.set(key, capability);
|
|
129
|
+
return capability;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Register an OAuth capability.
|
|
133
|
+
*
|
|
134
|
+
* There are two ways to configure OAuth:
|
|
135
|
+
*
|
|
136
|
+
* 1. Notion-managed providers:
|
|
137
|
+
* ```ts
|
|
138
|
+
* const worker = new Worker();
|
|
139
|
+
* export default worker;
|
|
140
|
+
*
|
|
141
|
+
* worker.oauth("googleAuth", {
|
|
142
|
+
* type: "notion_managed",
|
|
143
|
+
* name: "my-google-auth",
|
|
144
|
+
* provider: "google"
|
|
145
|
+
* })
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* 2. User-managed OAuth configuration:
|
|
149
|
+
* ```ts
|
|
150
|
+
* const worker = new Worker();
|
|
151
|
+
* export default worker;
|
|
152
|
+
*
|
|
153
|
+
* worker.oauth("myCustomAuth", {
|
|
154
|
+
* type: "user_managed",
|
|
155
|
+
* name: "my-custom-oauth",
|
|
156
|
+
* authorizationEndpoint: "https://provider.com/oauth/authorize",
|
|
157
|
+
* tokenEndpoint: "https://provider.com/oauth/token",
|
|
158
|
+
* scope: "read write",
|
|
159
|
+
* clientId: process.env.CLIENT_ID,
|
|
160
|
+
* clientSecret: process.env.CLIENT_SECRET,
|
|
161
|
+
* authorizationParams: {
|
|
162
|
+
* access_type: "offline",
|
|
163
|
+
* prompt: "consent"
|
|
164
|
+
* }
|
|
165
|
+
* })
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* @param key - The unique key used to register this OAuth capability.
|
|
169
|
+
* @param config - The OAuth configuration (Notion-managed or user-managed) for this capability.
|
|
170
|
+
* @returns The registered OAuth capability.
|
|
171
|
+
*/
|
|
172
|
+
oauth(key, config) {
|
|
173
|
+
this.#validateUniqueKey(key);
|
|
174
|
+
const capability = createOAuthCapability(key, config);
|
|
175
|
+
this.#capabilities.set(key, capability);
|
|
176
|
+
return capability;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get all registered capabilities (for discovery) without their handlers.
|
|
180
|
+
*/
|
|
181
|
+
get capabilities() {
|
|
182
|
+
return Array.from(this.#capabilities.values()).map((c) => ({
|
|
183
|
+
_tag: c._tag,
|
|
184
|
+
key: c.key,
|
|
185
|
+
config: c.config
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Execute a capability by key.
|
|
190
|
+
*
|
|
191
|
+
* @param key - The key of the capability to execute.
|
|
192
|
+
* @param context - The context to pass to the capability.
|
|
193
|
+
* @returns The result of the capability execution.
|
|
194
|
+
*/
|
|
195
|
+
async run(key, context) {
|
|
196
|
+
const capability = this.#capabilities.get(key);
|
|
197
|
+
if (!capability) {
|
|
198
|
+
throw new Error(`Capability "${key}" not found`);
|
|
199
|
+
}
|
|
200
|
+
if (capability._tag === "oauth") {
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Cannot run OAuth capability "${key}" - OAuth capabilities only provide configuration`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
return capability.handler(context);
|
|
206
|
+
}
|
|
207
|
+
#validateUniqueKey(key) {
|
|
208
|
+
if (!key || typeof key !== "string") {
|
|
209
|
+
throw new Error("Capability key must be a non-empty string");
|
|
210
|
+
}
|
|
211
|
+
if (this.#capabilities.has(key)) {
|
|
212
|
+
throw new Error(`Capability with key "${key}" already registered`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
export {
|
|
217
|
+
Worker
|
|
218
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@project-ajax/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"description": "An SDK for building workers for the Project Ajax platform",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -28,10 +28,6 @@
|
|
|
28
28
|
"./types": {
|
|
29
29
|
"types": "./dist/types.d.ts",
|
|
30
30
|
"default": "./dist/types.js"
|
|
31
|
-
},
|
|
32
|
-
"./sync": {
|
|
33
|
-
"types": "./dist/capabilities/sync.d.ts",
|
|
34
|
-
"default": "./dist/capabilities/sync.js"
|
|
35
31
|
}
|
|
36
32
|
},
|
|
37
33
|
"engines": {
|
|
@@ -8,14 +8,10 @@ import {
|
|
|
8
8
|
vi,
|
|
9
9
|
} from "vitest";
|
|
10
10
|
import { ExecutionError } from "../error.js";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
type AutomationContext,
|
|
14
|
-
automation,
|
|
15
|
-
type PageObjectResponse,
|
|
16
|
-
} from "./automation.js";
|
|
11
|
+
import type { AutomationContext, PageObjectResponse } from "./automation.js";
|
|
12
|
+
import { createAutomationCapability } from "./automation.js";
|
|
17
13
|
|
|
18
|
-
describe("
|
|
14
|
+
describe("createAutomationCapability", () => {
|
|
19
15
|
let stdoutSpy: Mock<typeof process.stdout.write>;
|
|
20
16
|
|
|
21
17
|
beforeEach(() => {
|
|
@@ -29,23 +25,21 @@ describe("automation", () => {
|
|
|
29
25
|
});
|
|
30
26
|
|
|
31
27
|
it("creates automation capability with correct structure", () => {
|
|
32
|
-
const
|
|
28
|
+
const capability = createAutomationCapability("testAutomation", {
|
|
33
29
|
title: "Test Automation",
|
|
34
30
|
description: "Test automation description",
|
|
35
31
|
execute: () => {},
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const result = automation(config);
|
|
32
|
+
});
|
|
39
33
|
|
|
40
|
-
expect(
|
|
41
|
-
expect(
|
|
42
|
-
expect(
|
|
43
|
-
expect(
|
|
34
|
+
expect(capability).toBeDefined();
|
|
35
|
+
expect(capability?._tag).toBe("automation");
|
|
36
|
+
expect(capability.config.title).toBe("Test Automation");
|
|
37
|
+
expect(capability.config.description).toBe("Test automation description");
|
|
44
38
|
});
|
|
45
39
|
|
|
46
40
|
it("executes automation without page data", async () => {
|
|
47
41
|
const executeFn = vi.fn();
|
|
48
|
-
const
|
|
42
|
+
const capability = createAutomationCapability("syncAutomation", {
|
|
49
43
|
title: "Sync Automation",
|
|
50
44
|
description: "Executes synchronously",
|
|
51
45
|
execute: executeFn,
|
|
@@ -56,7 +50,7 @@ describe("automation", () => {
|
|
|
56
50
|
actionType: "test_action",
|
|
57
51
|
};
|
|
58
52
|
|
|
59
|
-
await
|
|
53
|
+
await capability.handler(context);
|
|
60
54
|
|
|
61
55
|
expect(executeFn).toHaveBeenCalledWith(context);
|
|
62
56
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
@@ -66,7 +60,7 @@ describe("automation", () => {
|
|
|
66
60
|
|
|
67
61
|
it("executes automation with page data", async () => {
|
|
68
62
|
const executeFn = vi.fn();
|
|
69
|
-
const
|
|
63
|
+
const capability = createAutomationCapability("pageAutomation", {
|
|
70
64
|
title: "Page Automation",
|
|
71
65
|
description: "Processes page data",
|
|
72
66
|
execute: executeFn,
|
|
@@ -97,7 +91,7 @@ describe("automation", () => {
|
|
|
97
91
|
pageData,
|
|
98
92
|
};
|
|
99
93
|
|
|
100
|
-
await
|
|
94
|
+
await capability.handler(context);
|
|
101
95
|
|
|
102
96
|
expect(executeFn).toHaveBeenCalledWith(context);
|
|
103
97
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
@@ -106,7 +100,7 @@ describe("automation", () => {
|
|
|
106
100
|
});
|
|
107
101
|
|
|
108
102
|
it("handles execution error from function", async () => {
|
|
109
|
-
const
|
|
103
|
+
const capability = createAutomationCapability("errorAutomation", {
|
|
110
104
|
title: "Error Automation",
|
|
111
105
|
description: "Throws an error",
|
|
112
106
|
execute: () => {
|
|
@@ -119,7 +113,7 @@ describe("automation", () => {
|
|
|
119
113
|
actionType: "error_action",
|
|
120
114
|
};
|
|
121
115
|
|
|
122
|
-
await expect(
|
|
116
|
+
await expect(capability.handler(context)).rejects.toThrow(ExecutionError);
|
|
123
117
|
|
|
124
118
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
125
119
|
`\n<output>{"status":"error","error":{"name":"ExecutionError","message":"Error during worker execution: Error: Something went wrong"}}</output>\n`,
|
|
@@ -127,7 +121,7 @@ describe("automation", () => {
|
|
|
127
121
|
});
|
|
128
122
|
|
|
129
123
|
it("handles execution error with non-Error object", async () => {
|
|
130
|
-
const
|
|
124
|
+
const capability = createAutomationCapability("nonErrorAutomation", {
|
|
131
125
|
title: "Non-Error Automation",
|
|
132
126
|
description: "Throws a non-Error object",
|
|
133
127
|
execute: () => {
|
|
@@ -139,7 +133,7 @@ describe("automation", () => {
|
|
|
139
133
|
actionType: "string_error_action",
|
|
140
134
|
};
|
|
141
135
|
|
|
142
|
-
await expect(
|
|
136
|
+
await expect(capability.handler(context)).rejects.toThrow(ExecutionError);
|
|
143
137
|
|
|
144
138
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
145
139
|
`\n<output>{"status":"error","error":{"name":"ExecutionError","message":"Error during worker execution: String error"}}</output>\n`,
|
|
@@ -70,38 +70,24 @@ export interface AutomationHandlerResult {
|
|
|
70
70
|
description: string;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
export type AutomationCapability = ReturnType<
|
|
74
|
+
typeof createAutomationCapability
|
|
75
|
+
>;
|
|
76
|
+
|
|
73
77
|
/**
|
|
74
|
-
* Creates
|
|
75
|
-
* from database automations in Notion.
|
|
76
|
-
*
|
|
77
|
-
* Example:
|
|
78
|
-
*
|
|
79
|
-
* ```ts
|
|
80
|
-
* automation({
|
|
81
|
-
* title: "Send Welcome Email",
|
|
82
|
-
* description: "Sends a welcome email when a new user is added",
|
|
83
|
-
* execute: async (context) => {
|
|
84
|
-
* const { pageId, pageData } = context;
|
|
85
|
-
*
|
|
86
|
-
* // Access page properties from the Public API format
|
|
87
|
-
* if (pageData) {
|
|
88
|
-
* const name = pageData.properties.Name; // Access any property
|
|
89
|
-
* const status = pageData.properties.Status;
|
|
90
|
-
* console.log(`Processing: ${name}`);
|
|
91
|
-
* }
|
|
92
|
-
*
|
|
93
|
-
* // Your automation logic here
|
|
94
|
-
* await sendEmail(pageId);
|
|
95
|
-
* },
|
|
96
|
-
* })
|
|
97
|
-
* ```
|
|
78
|
+
* Creates an automation capability from configuration.
|
|
98
79
|
*
|
|
99
|
-
* @param
|
|
100
|
-
* @
|
|
80
|
+
* @param key - The unique name for this capability.
|
|
81
|
+
* @param config - The automation configuration.
|
|
82
|
+
* @returns The capability object.
|
|
101
83
|
*/
|
|
102
|
-
export function
|
|
84
|
+
export function createAutomationCapability(
|
|
85
|
+
key: string,
|
|
86
|
+
config: AutomationConfiguration,
|
|
87
|
+
) {
|
|
103
88
|
return {
|
|
104
|
-
_tag: "automation",
|
|
89
|
+
_tag: "automation" as const,
|
|
90
|
+
key,
|
|
105
91
|
config: {
|
|
106
92
|
title: config.title,
|
|
107
93
|
description: config.description,
|
|
@@ -109,12 +95,10 @@ export function automation(config: AutomationConfiguration) {
|
|
|
109
95
|
async handler(context: AutomationContext): Promise<void> {
|
|
110
96
|
try {
|
|
111
97
|
await config.execute(context);
|
|
112
|
-
// Write success result
|
|
113
98
|
process.stdout.write(
|
|
114
99
|
`\n<output>${JSON.stringify({ status: "success" })}</output>\n`,
|
|
115
100
|
);
|
|
116
101
|
} catch (err) {
|
|
117
|
-
// Convert error to ExecutionError and write it
|
|
118
102
|
const error = new ExecutionError(err);
|
|
119
103
|
process.stdout.write(
|
|
120
104
|
`\n<output>${JSON.stringify({ status: "error", error: { name: error.name, message: error.message } })}</output>\n`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { createOAuthCapability } from "./oauth.js";
|
|
3
3
|
|
|
4
4
|
describe("oauth", () => {
|
|
5
5
|
afterEach(() => {
|
|
@@ -9,42 +9,43 @@ describe("oauth", () => {
|
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it("creates notion-managed oauth capability with accessToken helper", async () => {
|
|
12
|
-
const
|
|
12
|
+
const capability = createOAuthCapability("googleAuth", {
|
|
13
13
|
name: "googleAuth",
|
|
14
14
|
provider: "google",
|
|
15
15
|
accessTokenExpireMs: 60_000,
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
expect(
|
|
19
|
-
expect(
|
|
20
|
-
expect(
|
|
21
|
-
expect(
|
|
22
|
-
|
|
18
|
+
expect(capability).toBeDefined();
|
|
19
|
+
expect(capability?._tag).toBe("oauth");
|
|
20
|
+
expect(capability.config.type).toBe("notion_managed");
|
|
21
|
+
expect(capability.config.accessTokenExpireMs).toBe(60_000);
|
|
22
|
+
|
|
23
|
+
expect(typeof capability.accessToken).toBe("function");
|
|
23
24
|
|
|
24
25
|
process.env.OAUTH_676F6F676C6541757468_ACCESS_TOKEN = "token-123";
|
|
25
|
-
await expect(
|
|
26
|
+
await expect(capability.accessToken()).resolves.toBe("token-123");
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
it("normalizes non-alphanumeric characters in the identifier", () => {
|
|
29
|
-
const
|
|
30
|
+
const capability = createOAuthCapability("googleCalendar", {
|
|
30
31
|
name: "google-calendar",
|
|
31
32
|
provider: "google",
|
|
32
33
|
accessTokenExpireMs: 3600_000,
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
expect(
|
|
36
|
-
|
|
37
|
-
);
|
|
38
|
-
expect(
|
|
36
|
+
expect(capability).toBeDefined();
|
|
37
|
+
expect(capability?._tag).toBe("oauth");
|
|
38
|
+
expect(capability.config.type).toBe("notion_managed");
|
|
39
|
+
expect(capability.config.accessTokenExpireMs).toBe(3600_000);
|
|
39
40
|
});
|
|
40
41
|
|
|
41
42
|
it("throws a helpful error when the token env var is missing", async () => {
|
|
42
|
-
const
|
|
43
|
+
const capability = createOAuthCapability("googleAuthMissing", {
|
|
43
44
|
name: "googleAuth",
|
|
44
45
|
provider: "google",
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
await expect(
|
|
48
|
+
await expect(capability.accessToken()).rejects.toThrow(
|
|
48
49
|
/Missing OAuth access token env var "OAUTH_676F6F676C6541757468_ACCESS_TOKEN"/,
|
|
49
50
|
);
|
|
50
51
|
});
|
|
@@ -88,46 +88,21 @@ export type OAuthConfiguration =
|
|
|
88
88
|
| NotionManagedOAuthConfiguration
|
|
89
89
|
| UserManagedOAuthConfiguration;
|
|
90
90
|
|
|
91
|
+
export type OAuthCapability = ReturnType<typeof createOAuthCapability>;
|
|
92
|
+
|
|
91
93
|
/**
|
|
92
94
|
* Creates an OAuth provider configuration for authenticating with third-party services.
|
|
93
95
|
*
|
|
94
|
-
* There are two ways to configure OAuth:
|
|
95
|
-
*
|
|
96
|
-
* 1. Notion-managed providers:
|
|
97
|
-
* ```ts
|
|
98
|
-
* oauth({
|
|
99
|
-
* type: "notion_managed",
|
|
100
|
-
* name: "my-google-auth",
|
|
101
|
-
* provider: "google"
|
|
102
|
-
* })
|
|
103
|
-
* ```
|
|
104
|
-
*
|
|
105
|
-
* 2. User-managed OAuth configuration:
|
|
106
|
-
* ```ts
|
|
107
|
-
* oauth({
|
|
108
|
-
* type: "user_managed",
|
|
109
|
-
* name: "my-custom-oauth",
|
|
110
|
-
* authorizationEndpoint: "https://provider.com/oauth/authorize",
|
|
111
|
-
* tokenEndpoint: "https://provider.com/oauth/token",
|
|
112
|
-
* scope: "read write",
|
|
113
|
-
* clientId: process.env.CLIENT_ID,
|
|
114
|
-
* clientSecret: process.env.CLIENT_SECRET,
|
|
115
|
-
* authorizationParams: {
|
|
116
|
-
* access_type: "offline",
|
|
117
|
-
* prompt: "consent"
|
|
118
|
-
* }
|
|
119
|
-
* })
|
|
120
|
-
* ```
|
|
121
|
-
*
|
|
122
96
|
* @param config - The OAuth configuration (Notion-managed or user-managed).
|
|
123
97
|
* @returns An OAuth provider definition.
|
|
124
98
|
*/
|
|
125
|
-
export function
|
|
99
|
+
export function createOAuthCapability(key: string, config: OAuthConfiguration) {
|
|
126
100
|
const envKey = oauthNameToEnvKey(config.name);
|
|
127
101
|
|
|
128
102
|
if ("provider" in config) {
|
|
129
103
|
return {
|
|
130
|
-
_tag: "oauth",
|
|
104
|
+
_tag: "oauth" as const,
|
|
105
|
+
key,
|
|
131
106
|
envKey,
|
|
132
107
|
async accessToken(): Promise<string> {
|
|
133
108
|
return readRequiredEnvVar(envKey, { name: config.name });
|
|
@@ -142,7 +117,8 @@ export function oauth(config: OAuthConfiguration) {
|
|
|
142
117
|
}
|
|
143
118
|
|
|
144
119
|
return {
|
|
145
|
-
_tag: "oauth",
|
|
120
|
+
_tag: "oauth" as const,
|
|
121
|
+
key,
|
|
146
122
|
envKey,
|
|
147
123
|
async accessToken(): Promise<string> {
|
|
148
124
|
return readRequiredEnvVar(envKey, { name: config.name });
|
package/src/capabilities/sync.ts
CHANGED
|
@@ -139,6 +139,8 @@ export type SyncHandlerResult<PK extends string, Context = unknown> = {
|
|
|
139
139
|
deleteUnreturnedPages?: boolean;
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
+
export type SyncCapability = ReturnType<typeof createSyncCapability>;
|
|
143
|
+
|
|
142
144
|
/**
|
|
143
145
|
* Creates a special handler for syncing third-party data to a collection.
|
|
144
146
|
*
|
|
@@ -146,13 +148,14 @@ export type SyncHandlerResult<PK extends string, Context = unknown> = {
|
|
|
146
148
|
* @returns A handler function that executes the sync function, and passes data
|
|
147
149
|
* needed to complete the sync back to the platform.
|
|
148
150
|
*/
|
|
149
|
-
export function
|
|
151
|
+
export function createSyncCapability<
|
|
150
152
|
PK extends string,
|
|
151
153
|
S extends Schema<PK>,
|
|
152
154
|
Context = unknown,
|
|
153
|
-
>(syncConfiguration: SyncConfiguration<PK, S, Context>) {
|
|
155
|
+
>(key: string, syncConfiguration: SyncConfiguration<PK, S, Context>) {
|
|
154
156
|
return {
|
|
155
|
-
_tag: "sync",
|
|
157
|
+
_tag: "sync" as const,
|
|
158
|
+
key,
|
|
156
159
|
config: {
|
|
157
160
|
primaryKeyProperty: syncConfiguration.primaryKeyProperty,
|
|
158
161
|
schema: syncConfiguration.schema,
|