@project-ajax/sdk 0.0.67 → 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.
Files changed (39) hide show
  1. package/dist/builder.d.ts +6 -1
  2. package/dist/builder.d.ts.map +1 -1
  3. package/dist/builder.js +7 -0
  4. package/dist/capabilities/automation.d.ts +8 -28
  5. package/dist/capabilities/automation.d.ts.map +1 -1
  6. package/dist/capabilities/automation.js +3 -2
  7. package/dist/capabilities/oauth.d.ts +6 -31
  8. package/dist/capabilities/oauth.d.ts.map +1 -1
  9. package/dist/capabilities/oauth.js +4 -2
  10. package/dist/capabilities/sync.d.ts +8 -4
  11. package/dist/capabilities/sync.d.ts.map +1 -1
  12. package/dist/capabilities/sync.js +3 -2
  13. package/dist/capabilities/tool.d.ts +5 -25
  14. package/dist/capabilities/tool.d.ts.map +1 -1
  15. package/dist/capabilities/tool.js +3 -2
  16. package/dist/index.d.ts +7 -9
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +4 -9
  19. package/dist/schema.d.ts +14 -2
  20. package/dist/schema.d.ts.map +1 -1
  21. package/dist/schema.js +4 -0
  22. package/dist/types.d.ts +32 -0
  23. package/dist/types.d.ts.map +1 -1
  24. package/dist/worker.d.ts +175 -0
  25. package/dist/worker.d.ts.map +1 -0
  26. package/dist/worker.js +218 -0
  27. package/package.json +1 -5
  28. package/src/builder.ts +12 -0
  29. package/src/capabilities/automation.test.ts +17 -23
  30. package/src/capabilities/automation.ts +14 -30
  31. package/src/capabilities/oauth.test.ts +16 -15
  32. package/src/capabilities/oauth.ts +7 -31
  33. package/src/capabilities/sync.ts +10 -4
  34. package/src/capabilities/tool.test.ts +105 -89
  35. package/src/capabilities/tool.ts +12 -31
  36. package/src/index.ts +7 -5
  37. package/src/schema.ts +18 -3
  38. package/src/types.ts +38 -0
  39. package/src/worker.ts +278 -0
@@ -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 oauth(config: OAuthConfiguration) {
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 });
@@ -7,6 +7,7 @@ import type {
7
7
  import type {
8
8
  Icon,
9
9
  PeopleValue,
10
+ PlaceValue,
10
11
  Schedule,
11
12
  SyncSchedule,
12
13
  TextValue,
@@ -20,7 +21,9 @@ type PropertyValueType<T extends PropertyConfiguration> = T extends {
20
21
  type: "people";
21
22
  }
22
23
  ? PeopleValue
23
- : TextValue;
24
+ : T extends { type: "place" }
25
+ ? PlaceValue
26
+ : TextValue;
24
27
 
25
28
  /**
26
29
  * An object representing a third-party record to be synced.
@@ -136,6 +139,8 @@ export type SyncHandlerResult<PK extends string, Context = unknown> = {
136
139
  deleteUnreturnedPages?: boolean;
137
140
  };
138
141
 
142
+ export type SyncCapability = ReturnType<typeof createSyncCapability>;
143
+
139
144
  /**
140
145
  * Creates a special handler for syncing third-party data to a collection.
141
146
  *
@@ -143,13 +148,14 @@ export type SyncHandlerResult<PK extends string, Context = unknown> = {
143
148
  * @returns A handler function that executes the sync function, and passes data
144
149
  * needed to complete the sync back to the platform.
145
150
  */
146
- export function sync<
151
+ export function createSyncCapability<
147
152
  PK extends string,
148
153
  S extends Schema<PK>,
149
154
  Context = unknown,
150
- >(syncConfiguration: SyncConfiguration<PK, S, Context>) {
155
+ >(key: string, syncConfiguration: SyncConfiguration<PK, S, Context>) {
151
156
  return {
152
- _tag: "sync",
157
+ _tag: "sync" as const,
158
+ key,
153
159
  config: {
154
160
  primaryKeyProperty: syncConfiguration.primaryKeyProperty,
155
161
  schema: syncConfiguration.schema,
@@ -8,13 +8,13 @@ import {
8
8
  vi,
9
9
  } from "vitest";
10
10
  import {
11
+ createToolCapability,
11
12
  InvalidToolInputError,
12
13
  InvalidToolOutputError,
13
14
  ToolExecutionError,
14
- tool,
15
15
  } from "./tool.js";
16
16
 
17
- describe("tool", () => {
17
+ describe("Worker.tool", () => {
18
18
  let stdoutSpy: Mock<typeof process.stdout.write>;
19
19
 
20
20
  beforeEach(() => {
@@ -28,28 +28,28 @@ describe("tool", () => {
28
28
  });
29
29
 
30
30
  it("sync execution", async () => {
31
- const myTool = tool<{ name: string }, string>({
32
- title: "Say Hello",
33
- description: "Greet a user",
34
- schema: {
35
- type: "object",
36
- properties: {
37
- name: { type: "string" },
31
+ const capability = createToolCapability<{ name: string }, string>(
32
+ "sayHello",
33
+ {
34
+ title: "Say Hello",
35
+ description: "Greet a user",
36
+ schema: {
37
+ type: "object",
38
+ properties: {
39
+ name: { type: "string" },
40
+ },
41
+ required: ["name"],
42
+ additionalProperties: false,
43
+ },
44
+ execute: (input: { name: string }) => {
45
+ return `Hello, ${input.name}!`;
38
46
  },
39
- required: ["name"],
40
- additionalProperties: false,
41
- },
42
- execute: (input) => {
43
- return `Hello, ${input.name}!`;
44
47
  },
45
- });
48
+ );
46
49
 
47
- const result = await myTool.handler({ name: "Alice" });
50
+ const result = await capability.handler({ name: "Alice" });
48
51
 
49
- expect(result._tag).toBe("success");
50
- if (result._tag === "success") {
51
- expect(result.value).toBe("Hello, Alice!");
52
- }
52
+ expect(result).toEqual({ _tag: "success", value: "Hello, Alice!" });
53
53
 
54
54
  expect(stdoutSpy).toHaveBeenCalledWith(
55
55
  `\n<output>"Hello, Alice!"</output>\n`,
@@ -57,30 +57,33 @@ describe("tool", () => {
57
57
  });
58
58
 
59
59
  it("async execution", async () => {
60
- const myTool = tool<{ id: number }, { data: string }>({
61
- title: "Fetch Data",
62
- description: "Fetch data asynchronously",
63
- schema: {
64
- type: "object",
65
- properties: {
66
- id: { type: "number" },
60
+ const capability = createToolCapability<{ id: number }, { data: string }>(
61
+ "fetchData",
62
+ {
63
+ title: "Fetch Data",
64
+ description: "Fetch data asynchronously",
65
+ schema: {
66
+ type: "object",
67
+ properties: {
68
+ id: { type: "number" },
69
+ },
70
+ required: ["id"],
71
+ additionalProperties: false,
72
+ },
73
+ execute: async (input: { id: number }) => {
74
+ // Simulate async operation
75
+ await new Promise((resolve) => setTimeout(resolve, 10));
76
+ return { data: `Data for ID ${input.id}` };
67
77
  },
68
- required: ["id"],
69
- additionalProperties: false,
70
- },
71
- execute: async (input) => {
72
- // Simulate async operation
73
- await new Promise((resolve) => setTimeout(resolve, 10));
74
- return { data: `Data for ID ${input.id}` };
75
78
  },
76
- });
79
+ );
77
80
 
78
- const result = await myTool.handler({ id: 42 });
81
+ const result = await capability.handler({ id: 42 });
79
82
 
80
- expect(result._tag).toBe("success");
81
- if (result._tag === "success") {
82
- expect(result.value).toEqual({ data: "Data for ID 42" });
83
- }
83
+ expect(result).toEqual({
84
+ _tag: "success",
85
+ value: { data: "Data for ID 42" },
86
+ });
84
87
 
85
88
  expect(stdoutSpy).toHaveBeenCalledWith(
86
89
  `\n<output>{"data":"Data for ID 42"}</output>\n`,
@@ -88,27 +91,31 @@ describe("tool", () => {
88
91
  });
89
92
 
90
93
  it("execution error", async () => {
91
- const myTool = tool<Record<string, never>, string>({
92
- title: "Throw Error",
93
- description: "Throws an error",
94
- schema: {
95
- type: "object",
96
- properties: {},
97
- required: [],
98
- additionalProperties: false,
99
- },
100
- execute: () => {
101
- throw new Error("Something went wrong");
94
+ const capability = createToolCapability<Record<string, never>, string>(
95
+ "throwError",
96
+ {
97
+ title: "Throw Error",
98
+ description: "Throws an error",
99
+ schema: {
100
+ type: "object",
101
+ properties: {},
102
+ required: [],
103
+ additionalProperties: false,
104
+ },
105
+ execute: () => {
106
+ throw new Error("Something went wrong");
107
+ },
102
108
  },
103
- });
109
+ );
104
110
 
105
- const result = await myTool.handler({});
111
+ const result = (await capability.handler({})) as {
112
+ _tag: "error";
113
+ error: ToolExecutionError;
114
+ };
106
115
 
107
116
  expect(result._tag).toBe("error");
108
- if (result._tag === "error") {
109
- expect(result.error).toBeInstanceOf(ToolExecutionError);
110
- expect(result.error.message).toBe("Something went wrong");
111
- }
117
+ expect(result.error).toBeInstanceOf(ToolExecutionError);
118
+ expect(result.error.message).toBe("Something went wrong");
112
119
 
113
120
  expect(stdoutSpy).toHaveBeenCalledWith(
114
121
  `\n<output>{"_tag":"error","error":{"name":"ToolExecutionError","message":"Something went wrong"}}</output>\n`,
@@ -116,29 +123,33 @@ describe("tool", () => {
116
123
  });
117
124
 
118
125
  it("invalid input", async () => {
119
- const myTool = tool<{ name: string }, string>({
120
- title: "Say Hello",
121
- description: "Requires a name property",
122
- schema: {
123
- type: "object",
124
- properties: {
125
- name: { type: "string" },
126
+ const capability = createToolCapability<{ name: string }, string>(
127
+ "sayHelloStrict",
128
+ {
129
+ title: "Say Hello",
130
+ description: "Requires a name property",
131
+ schema: {
132
+ type: "object",
133
+ properties: {
134
+ name: { type: "string" },
135
+ },
136
+ required: ["name"],
137
+ additionalProperties: false,
138
+ },
139
+ execute: (input: { name: string }) => {
140
+ return `Hello, ${input.name}!`;
126
141
  },
127
- required: ["name"],
128
- additionalProperties: false,
129
- },
130
- execute: (input) => {
131
- return `Hello, ${input.name}!`;
132
142
  },
133
- });
143
+ );
134
144
 
135
- const result = await myTool.handler({ age: 25 });
145
+ const result = (await capability.handler({ age: 25 })) as {
146
+ _tag: "error";
147
+ error: InvalidToolInputError;
148
+ };
136
149
 
137
150
  expect(result._tag).toBe("error");
138
- if (result._tag === "error") {
139
- expect(result.error).toBeInstanceOf(InvalidToolInputError);
140
- expect(result.error.message).toContain("name");
141
- }
151
+ expect(result.error).toBeInstanceOf(InvalidToolInputError);
152
+ expect(result.error.message).toContain("name");
142
153
 
143
154
  expect(stdoutSpy).toHaveBeenCalledWith(
144
155
  expect.stringContaining(
@@ -148,7 +159,10 @@ describe("tool", () => {
148
159
  });
149
160
 
150
161
  it("invalid output", async () => {
151
- const myTool = tool<Record<string, never>, { result: string }>({
162
+ const capability = createToolCapability<
163
+ Record<string, never>,
164
+ { result: string }
165
+ >("invalidOutput", {
152
166
  title: "Return Invalid Output",
153
167
  description: "Returns output that doesn't match schema",
154
168
  schema: {
@@ -171,13 +185,14 @@ describe("tool", () => {
171
185
  },
172
186
  });
173
187
 
174
- const result = await myTool.handler({});
188
+ const result = (await capability.handler({})) as {
189
+ _tag: "error";
190
+ error: InvalidToolOutputError;
191
+ };
175
192
 
176
193
  expect(result._tag).toBe("error");
177
- if (result._tag === "error") {
178
- expect(result.error).toBeInstanceOf(InvalidToolOutputError);
179
- expect(result.error.message).toContain("result");
180
- }
194
+ expect(result.error).toBeInstanceOf(InvalidToolOutputError);
195
+ expect(result.error.message).toContain("result");
181
196
 
182
197
  expect(stdoutSpy).toHaveBeenCalledWith(
183
198
  expect.stringContaining(
@@ -187,10 +202,10 @@ describe("tool", () => {
187
202
  });
188
203
 
189
204
  it("invalid output with custom output schema", async () => {
190
- const myTool = tool<
205
+ const capability = createToolCapability<
191
206
  { value: number },
192
207
  { doubled: number; message: string }
193
- >({
208
+ >("customOutput", {
194
209
  title: "Custom Output",
195
210
  description: "Has custom output schema",
196
211
  schema: {
@@ -211,20 +226,21 @@ describe("tool", () => {
211
226
  additionalProperties: false,
212
227
  },
213
228
  // @ts-expect-error Testing invalid output - intentionally missing message property
214
- execute: (input) => {
229
+ execute: (input: { value: number }) => {
215
230
  return {
216
231
  doubled: input.value * 2,
217
232
  };
218
233
  },
219
234
  });
220
235
 
221
- const result = await myTool.handler({ value: 5 });
236
+ const result = (await capability.handler({ value: 5 })) as {
237
+ _tag: "error";
238
+ error: InvalidToolOutputError;
239
+ };
222
240
 
223
241
  expect(result._tag).toBe("error");
224
- if (result._tag === "error") {
225
- expect(result.error).toBeInstanceOf(InvalidToolOutputError);
226
- expect(result.error.message).toContain("message");
227
- }
242
+ expect(result.error).toBeInstanceOf(InvalidToolOutputError);
243
+ expect(result.error.message).toContain("message");
228
244
 
229
245
  expect(stdoutSpy).toHaveBeenCalledWith(
230
246
  expect.stringContaining(
@@ -1,12 +1,5 @@
1
1
  import { Ajv, type JSONSchemaType } from "ajv";
2
-
3
- type JSONValue =
4
- | string
5
- | number
6
- | boolean
7
- | null
8
- | JSONValue[]
9
- | { [key: string]: JSONValue };
2
+ import type { JSONValue } from "../types.js";
10
3
 
11
4
  export interface ToolConfiguration<
12
5
  I extends JSONValue,
@@ -70,34 +63,21 @@ export class ToolExecutionError extends Error {
70
63
  }
71
64
  }
72
65
 
66
+ export type ToolCapability<
67
+ I extends JSONValue,
68
+ O extends JSONValue = JSONValue,
69
+ > = ReturnType<typeof createToolCapability<I, O>>;
70
+
73
71
  /**
74
72
  * Creates a capability definition for a tool to be used by an agent.
75
73
  *
76
- * Example:
77
- *
78
- * ```ts
79
- * tool<{ name: string }>({
80
- * title: "Say Hello",
81
- * description: "Say hello to the user",
82
- * schema: {
83
- * type: "object",
84
- * properties: {
85
- * name: { type: "string" },
86
- * },
87
- * required: ["name"],
88
- * },
89
- * execute: ({ name }) => {
90
- * return `Hello, ${name}!`;
91
- * },
92
- * })
93
- * ```
94
- *
95
74
  * @param config - The configuration for the tool.
96
75
  * @returns A capability definition for the tool.
97
76
  */
98
- export function tool<I extends JSONValue, O extends JSONValue = JSONValue>(
99
- config: ToolConfiguration<I, O>,
100
- ) {
77
+ export function createToolCapability<
78
+ I extends JSONValue,
79
+ O extends JSONValue = JSONValue,
80
+ >(key: string, config: ToolConfiguration<I, O>) {
101
81
  const ajv = new Ajv();
102
82
  const validateInput = ajv.compile(config.schema);
103
83
  const validateOutput = config.outputSchema
@@ -105,7 +85,8 @@ export function tool<I extends JSONValue, O extends JSONValue = JSONValue>(
105
85
  : null;
106
86
 
107
87
  return {
108
- _tag: "tool",
88
+ _tag: "tool" as const,
89
+ key,
109
90
  config: {
110
91
  title: config.title,
111
92
  description: config.description,
package/src/index.ts CHANGED
@@ -1,27 +1,29 @@
1
- export { emojiIcon, imageIcon, notionIcon } from "./builder.js";
1
+ export { emojiIcon, imageIcon, notionIcon, place } from "./builder.js";
2
2
  export type {
3
+ AutomationCapability,
3
4
  AutomationConfiguration,
4
5
  AutomationContext,
5
6
  PageObjectResponse,
6
7
  } from "./capabilities/automation.js";
7
- export { automation } from "./capabilities/automation.js";
8
8
  export type {
9
9
  NotionManagedOAuthConfiguration,
10
+ OAuthCapability,
10
11
  OAuthConfiguration,
11
12
  UserManagedOAuthConfiguration,
12
13
  } from "./capabilities/oauth.js";
13
- export { oauth } from "./capabilities/oauth.js";
14
14
  export type {
15
+ SyncCapability,
15
16
  SyncConfiguration,
16
17
  SyncExecutionResult,
17
18
  SyncedObject,
18
19
  } from "./capabilities/sync.js";
19
- export { sync } from "./capabilities/sync.js";
20
- export { tool } from "./capabilities/tool.js";
20
+ export type { ToolCapability, ToolConfiguration } from "./capabilities/tool.js";
21
21
  export type {
22
22
  Icon,
23
23
  ImageIcon,
24
24
  NoticonColor,
25
25
  NoticonName,
26
+ PlaceValue,
26
27
  Schedule,
27
28
  } from "./types.js";
29
+ export { Worker } from "./worker.js";
package/src/schema.ts CHANGED
@@ -22,7 +22,8 @@ export type PropertyType =
22
22
  | "select"
23
23
  | "multi_select"
24
24
  | "status"
25
- | "people";
25
+ | "people"
26
+ | "place";
26
27
 
27
28
  /**
28
29
  * Definition of a single property in a sync schema.
@@ -62,10 +63,17 @@ export type PropertyConfiguration =
62
63
  type: "status";
63
64
  groups: StatusGroup[];
64
65
  }
65
- | { type: "people" };
66
+ | { type: "people" }
67
+ | { type: "place" };
66
68
 
67
69
  export type Schema<PK extends string> = {
68
- dataSourceTitle: string;
70
+ /**
71
+ * The default name for the database when it is first created.
72
+ *
73
+ * Updating this after the database has been created will not change the
74
+ * name of the database.
75
+ */
76
+ defaultName: string;
69
77
  /**
70
78
  * Optional icon to use as the icon for the database page.
71
79
  * If not provided, defaults to 📋.
@@ -176,3 +184,10 @@ export function status(config: {
176
184
  export function people(): PropertyConfiguration {
177
185
  return { type: "people" };
178
186
  }
187
+
188
+ /**
189
+ * Creates a place property definition for storing geographic locations.
190
+ */
191
+ export function place(): PropertyConfiguration {
192
+ return { type: "place" };
193
+ }
package/src/types.ts CHANGED
@@ -1,3 +1,14 @@
1
+ /**
2
+ * A JSON value is a string, number, boolean, null, array, or object.
3
+ */
4
+ export type JSONValue =
5
+ | string
6
+ | number
7
+ | boolean
8
+ | null
9
+ | JSONValue[]
10
+ | { [key: string]: JSONValue };
11
+
1
12
  /**
2
13
  * A text token is a tuple where the first element is the text content
3
14
  * and optional subsequent elements are formatting annotations.
@@ -188,6 +199,33 @@ export type PeopleValue = PersonReference[];
188
199
 
189
200
  export type { NoticonName } from "./icon-names.js";
190
201
 
202
+ /**
203
+ * Place value representing a geographic location.
204
+ * Used for place properties in databases.
205
+ */
206
+ export interface PlaceValue {
207
+ /**
208
+ * Latitude coordinate (required)
209
+ */
210
+ lat: number;
211
+ /**
212
+ * Longitude coordinate (required)
213
+ */
214
+ lon: number;
215
+ /**
216
+ * Optional display name for the location
217
+ */
218
+ name?: string;
219
+ /**
220
+ * Optional street address
221
+ */
222
+ address?: string;
223
+ /**
224
+ * Optional Google Place ID for the location
225
+ */
226
+ googlePlaceId?: string;
227
+ }
228
+
191
229
  /**
192
230
  * Time units for schedule intervals.
193
231
  * - "m": minutes