@project-ajax/sdk 0.0.66 → 0.0.67

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.
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Configuration for a Notion-managed OAuth provider.
3
+ *
4
+ * Notion owns the OAuth app credentials (client ID/secret) and the backend has
5
+ * pre-configured provider settings.
6
+ */
7
+ export interface NotionManagedOAuthConfiguration {
8
+ /**
9
+ * The unique identifier for this OAuth provider instance.
10
+ */
11
+ name: string;
12
+ /**
13
+ * The pre-configured provider to use (e.g., "google", "github", "salesforce").
14
+ * The backend will use this to look up the OAuth configuration.
15
+ */
16
+ provider: string;
17
+ /**
18
+ * Optional default access token expiry (in milliseconds) to use when the OAuth provider
19
+ * does not return `expires_in` in token responses.
20
+ *
21
+ * Some providers (e.g. Salesforce in certain configurations) may omit expiry information.
22
+ */
23
+ accessTokenExpireMs?: number;
24
+ }
25
+ /**
26
+ * Configuration for a user-managed OAuth provider.
27
+ *
28
+ * You own the OAuth app credentials and must explicitly provide endpoints and
29
+ * other OAuth parameters.
30
+ */
31
+ export interface UserManagedOAuthConfiguration {
32
+ /**
33
+ * The unique identifier for this OAuth provider instance.
34
+ */
35
+ name: string;
36
+ /**
37
+ * The client ID for the OAuth app.
38
+ */
39
+ clientId: string;
40
+ /**
41
+ * The client secret for the OAuth app.
42
+ */
43
+ clientSecret: string;
44
+ /**
45
+ * The OAuth 2.0 authorization endpoint URL.
46
+ */
47
+ authorizationEndpoint: string;
48
+ /**
49
+ * The OAuth 2.0 token endpoint URL.
50
+ */
51
+ tokenEndpoint: string;
52
+ /**
53
+ * The OAuth scope(s) to request.
54
+ */
55
+ scope: string;
56
+ /**
57
+ * Optional additional authorization parameters to include in the authorization request.
58
+ */
59
+ authorizationParams?: Record<string, string>;
60
+ /**
61
+ * Optional callback URL for OAuth redirect.
62
+ */
63
+ callbackUrl?: string;
64
+ /**
65
+ * Optional default access token expiry (in milliseconds) to use when the OAuth provider
66
+ * does not return `expires_in` in token responses.
67
+ *
68
+ * Some providers (e.g. Salesforce in certain configurations) may omit expiry information.
69
+ */
70
+ accessTokenExpireMs?: number;
71
+ }
72
+ /**
73
+ * Union type representing either Notion-managed or user-managed OAuth configuration.
74
+ */
75
+ export type OAuthConfiguration = NotionManagedOAuthConfiguration | UserManagedOAuthConfiguration;
76
+ /**
77
+ * Creates an OAuth provider configuration for authenticating with third-party services.
78
+ *
79
+ * There are two ways to configure OAuth:
80
+ *
81
+ * 1. Notion-managed providers:
82
+ * ```ts
83
+ * oauth({
84
+ * type: "notion_managed",
85
+ * name: "my-google-auth",
86
+ * provider: "google"
87
+ * })
88
+ * ```
89
+ *
90
+ * 2. User-managed OAuth configuration:
91
+ * ```ts
92
+ * oauth({
93
+ * type: "user_managed",
94
+ * name: "my-custom-oauth",
95
+ * authorizationEndpoint: "https://provider.com/oauth/authorize",
96
+ * tokenEndpoint: "https://provider.com/oauth/token",
97
+ * scope: "read write",
98
+ * clientId: process.env.CLIENT_ID,
99
+ * clientSecret: process.env.CLIENT_SECRET,
100
+ * authorizationParams: {
101
+ * access_type: "offline",
102
+ * prompt: "consent"
103
+ * }
104
+ * })
105
+ * ```
106
+ *
107
+ * @param config - The OAuth configuration (Notion-managed or user-managed).
108
+ * @returns An OAuth provider definition.
109
+ */
110
+ export declare function oauth(config: OAuthConfiguration): {
111
+ _tag: string;
112
+ envKey: string;
113
+ accessToken(): Promise<string>;
114
+ config: {
115
+ type: "notion_managed";
116
+ name: string;
117
+ provider: string;
118
+ accessTokenExpireMs: number | undefined;
119
+ authorizationEndpoint?: never;
120
+ tokenEndpoint?: never;
121
+ scope?: never;
122
+ clientId?: never;
123
+ clientSecret?: never;
124
+ authorizationParams?: never;
125
+ callbackUrl?: never;
126
+ };
127
+ } | {
128
+ _tag: string;
129
+ envKey: string;
130
+ accessToken(): Promise<string>;
131
+ config: {
132
+ type: "user_managed";
133
+ name: string;
134
+ authorizationEndpoint: string;
135
+ tokenEndpoint: string;
136
+ scope: string;
137
+ clientId: string;
138
+ clientSecret: string;
139
+ authorizationParams: Record<string, string> | undefined;
140
+ callbackUrl: string | undefined;
141
+ accessTokenExpireMs: number | undefined;
142
+ provider?: never;
143
+ };
144
+ };
145
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/capabilities/oauth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,+BAA+B;IAC/C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC7C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,qBAAqB,EAAE,MAAM,CAAC;IAE9B;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC3B,+BAA+B,GAC/B,6BAA6B,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,kBAAkB;;;mBAOxB,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;mBAehB,OAAO,CAAC,MAAM,CAAC;;;;;;;;;;;;;;EAgBrC"}
@@ -0,0 +1,53 @@
1
+ function oauth(config) {
2
+ const envKey = oauthNameToEnvKey(config.name);
3
+ if ("provider" in config) {
4
+ return {
5
+ _tag: "oauth",
6
+ envKey,
7
+ async accessToken() {
8
+ return readRequiredEnvVar(envKey, { name: config.name });
9
+ },
10
+ config: {
11
+ type: "notion_managed",
12
+ name: config.name,
13
+ provider: config.provider,
14
+ accessTokenExpireMs: config.accessTokenExpireMs
15
+ }
16
+ };
17
+ }
18
+ return {
19
+ _tag: "oauth",
20
+ envKey,
21
+ async accessToken() {
22
+ return readRequiredEnvVar(envKey, { name: config.name });
23
+ },
24
+ config: {
25
+ type: "user_managed",
26
+ name: config.name,
27
+ authorizationEndpoint: config.authorizationEndpoint,
28
+ tokenEndpoint: config.tokenEndpoint,
29
+ scope: config.scope,
30
+ clientId: config.clientId,
31
+ clientSecret: config.clientSecret,
32
+ authorizationParams: config.authorizationParams,
33
+ callbackUrl: config.callbackUrl,
34
+ accessTokenExpireMs: config.accessTokenExpireMs
35
+ }
36
+ };
37
+ }
38
+ function oauthNameToEnvKey(identifier) {
39
+ const encoded = Buffer.from(identifier).toString("hex").toUpperCase();
40
+ return `OAUTH_${encoded}_ACCESS_TOKEN`;
41
+ }
42
+ function readRequiredEnvVar(key, context) {
43
+ const value = process.env[key];
44
+ if (value) {
45
+ return value;
46
+ }
47
+ throw new Error(
48
+ `Missing OAuth access token env var "${key}" (name: "${context.name}"). Make sure you've completed OAuth for this capability and are running inside the worker runtime.`
49
+ );
50
+ }
51
+ export {
52
+ oauth
53
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=oauth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.test.d.ts","sourceRoot":"","sources":["../../src/capabilities/oauth.test.ts"],"names":[],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { emojiIcon, imageIcon, notionIcon } from "./builder.js";
2
2
  export type { AutomationConfiguration, AutomationContext, PageObjectResponse, } from "./capabilities/automation.js";
3
3
  export { automation } from "./capabilities/automation.js";
4
+ export type { NotionManagedOAuthConfiguration, OAuthConfiguration, UserManagedOAuthConfiguration, } from "./capabilities/oauth.js";
5
+ export { oauth } from "./capabilities/oauth.js";
4
6
  export type { SyncConfiguration, SyncExecutionResult, SyncedObject, } from "./capabilities/sync.js";
5
7
  export { sync } from "./capabilities/sync.js";
6
8
  export { tool } from "./capabilities/tool.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EACX,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,GAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,YAAY,EACX,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,YAAY,EACX,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,QAAQ,GACR,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EACX,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,GAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,YAAY,EACX,+BAA+B,EAC/B,kBAAkB,EAClB,6BAA6B,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,YAAY,EACX,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9C,YAAY,EACX,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,WAAW,EACX,QAAQ,GACR,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { emojiIcon, imageIcon, notionIcon } from "./builder.js";
2
2
  import { automation } from "./capabilities/automation.js";
3
+ import { oauth } from "./capabilities/oauth.js";
3
4
  import { sync } from "./capabilities/sync.js";
4
5
  import { tool } from "./capabilities/tool.js";
5
6
  export {
@@ -7,6 +8,7 @@ export {
7
8
  emojiIcon,
8
9
  imageIcon,
9
10
  notionIcon,
11
+ oauth,
10
12
  sync,
11
13
  tool
12
14
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-ajax/sdk",
3
- "version": "0.0.66",
3
+ "version": "0.0.67",
4
4
  "description": "An SDK for building workers for the Project Ajax platform",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -0,0 +1,51 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { oauth } from "./oauth.js";
3
+
4
+ describe("oauth", () => {
5
+ afterEach(() => {
6
+ // Clean up env changes between tests
7
+ delete process.env.OAUTH_676F6F676C6541757468_ACCESS_TOKEN;
8
+ delete process.env.OAUTH_676F6F676C652D63616C656E646172_ACCESS_TOKEN;
9
+ });
10
+
11
+ it("creates notion-managed oauth capability with accessToken helper", async () => {
12
+ const myOauth = oauth({
13
+ name: "googleAuth",
14
+ provider: "google",
15
+ accessTokenExpireMs: 60_000,
16
+ });
17
+
18
+ expect(myOauth._tag).toBe("oauth");
19
+ expect(myOauth.config.type).toBe("notion_managed");
20
+ expect(myOauth.config.accessTokenExpireMs).toBe(60_000);
21
+ expect(myOauth.envKey).toBe("OAUTH_676F6F676C6541757468_ACCESS_TOKEN");
22
+ expect(typeof myOauth.accessToken).toBe("function");
23
+
24
+ process.env.OAUTH_676F6F676C6541757468_ACCESS_TOKEN = "token-123";
25
+ await expect(myOauth.accessToken()).resolves.toBe("token-123");
26
+ });
27
+
28
+ it("normalizes non-alphanumeric characters in the identifier", () => {
29
+ const myOauth = oauth({
30
+ name: "google-calendar",
31
+ provider: "google",
32
+ accessTokenExpireMs: 3600_000,
33
+ });
34
+
35
+ expect(myOauth.envKey).toBe(
36
+ "OAUTH_676F6F676C652D63616C656E646172_ACCESS_TOKEN",
37
+ );
38
+ expect(myOauth.config.accessTokenExpireMs).toBe(3600_000);
39
+ });
40
+
41
+ it("throws a helpful error when the token env var is missing", async () => {
42
+ const myOauth = oauth({
43
+ name: "googleAuth",
44
+ provider: "google",
45
+ });
46
+
47
+ await expect(myOauth.accessToken()).rejects.toThrow(
48
+ /Missing OAuth access token env var "OAUTH_676F6F676C6541757468_ACCESS_TOKEN"/,
49
+ );
50
+ });
51
+ });
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Configuration for a Notion-managed OAuth provider.
3
+ *
4
+ * Notion owns the OAuth app credentials (client ID/secret) and the backend has
5
+ * pre-configured provider settings.
6
+ */
7
+ export interface NotionManagedOAuthConfiguration {
8
+ /**
9
+ * The unique identifier for this OAuth provider instance.
10
+ */
11
+ name: string;
12
+
13
+ /**
14
+ * The pre-configured provider to use (e.g., "google", "github", "salesforce").
15
+ * The backend will use this to look up the OAuth configuration.
16
+ */
17
+ provider: string;
18
+
19
+ /**
20
+ * Optional default access token expiry (in milliseconds) to use when the OAuth provider
21
+ * does not return `expires_in` in token responses.
22
+ *
23
+ * Some providers (e.g. Salesforce in certain configurations) may omit expiry information.
24
+ */
25
+ accessTokenExpireMs?: number;
26
+ }
27
+
28
+ /**
29
+ * Configuration for a user-managed OAuth provider.
30
+ *
31
+ * You own the OAuth app credentials and must explicitly provide endpoints and
32
+ * other OAuth parameters.
33
+ */
34
+ export interface UserManagedOAuthConfiguration {
35
+ /**
36
+ * The unique identifier for this OAuth provider instance.
37
+ */
38
+ name: string;
39
+
40
+ /**
41
+ * The client ID for the OAuth app.
42
+ */
43
+ clientId: string;
44
+
45
+ /**
46
+ * The client secret for the OAuth app.
47
+ */
48
+ clientSecret: string;
49
+
50
+ /**
51
+ * The OAuth 2.0 authorization endpoint URL.
52
+ */
53
+ authorizationEndpoint: string;
54
+
55
+ /**
56
+ * The OAuth 2.0 token endpoint URL.
57
+ */
58
+ tokenEndpoint: string;
59
+
60
+ /**
61
+ * The OAuth scope(s) to request.
62
+ */
63
+ scope: string;
64
+
65
+ /**
66
+ * Optional additional authorization parameters to include in the authorization request.
67
+ */
68
+ authorizationParams?: Record<string, string>;
69
+
70
+ /**
71
+ * Optional callback URL for OAuth redirect.
72
+ */
73
+ callbackUrl?: string;
74
+
75
+ /**
76
+ * Optional default access token expiry (in milliseconds) to use when the OAuth provider
77
+ * does not return `expires_in` in token responses.
78
+ *
79
+ * Some providers (e.g. Salesforce in certain configurations) may omit expiry information.
80
+ */
81
+ accessTokenExpireMs?: number;
82
+ }
83
+
84
+ /**
85
+ * Union type representing either Notion-managed or user-managed OAuth configuration.
86
+ */
87
+ export type OAuthConfiguration =
88
+ | NotionManagedOAuthConfiguration
89
+ | UserManagedOAuthConfiguration;
90
+
91
+ /**
92
+ * Creates an OAuth provider configuration for authenticating with third-party services.
93
+ *
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
+ * @param config - The OAuth configuration (Notion-managed or user-managed).
123
+ * @returns An OAuth provider definition.
124
+ */
125
+ export function oauth(config: OAuthConfiguration) {
126
+ const envKey = oauthNameToEnvKey(config.name);
127
+
128
+ if ("provider" in config) {
129
+ return {
130
+ _tag: "oauth",
131
+ envKey,
132
+ async accessToken(): Promise<string> {
133
+ return readRequiredEnvVar(envKey, { name: config.name });
134
+ },
135
+ config: {
136
+ type: "notion_managed" as const,
137
+ name: config.name,
138
+ provider: config.provider,
139
+ accessTokenExpireMs: config.accessTokenExpireMs,
140
+ },
141
+ };
142
+ }
143
+
144
+ return {
145
+ _tag: "oauth",
146
+ envKey,
147
+ async accessToken(): Promise<string> {
148
+ return readRequiredEnvVar(envKey, { name: config.name });
149
+ },
150
+ config: {
151
+ type: "user_managed" as const,
152
+ name: config.name,
153
+ authorizationEndpoint: config.authorizationEndpoint,
154
+ tokenEndpoint: config.tokenEndpoint,
155
+ scope: config.scope,
156
+ clientId: config.clientId,
157
+ clientSecret: config.clientSecret,
158
+ authorizationParams: config.authorizationParams,
159
+ callbackUrl: config.callbackUrl,
160
+ accessTokenExpireMs: config.accessTokenExpireMs,
161
+ },
162
+ };
163
+ }
164
+
165
+ function oauthNameToEnvKey(identifier: string): string {
166
+ const encoded = Buffer.from(identifier).toString("hex").toUpperCase();
167
+
168
+ return `OAUTH_${encoded}_ACCESS_TOKEN`;
169
+ }
170
+
171
+ function readRequiredEnvVar(key: string, context: { name: string }): string {
172
+ const value = process.env[key];
173
+ if (value) {
174
+ return value;
175
+ }
176
+
177
+ throw new Error(
178
+ `Missing OAuth access token env var "${key}" (name: "${context.name}"). ` +
179
+ `Make sure you've completed OAuth for this capability and are running inside the worker runtime.`,
180
+ );
181
+ }
package/src/index.ts CHANGED
@@ -5,6 +5,12 @@ export type {
5
5
  PageObjectResponse,
6
6
  } from "./capabilities/automation.js";
7
7
  export { automation } from "./capabilities/automation.js";
8
+ export type {
9
+ NotionManagedOAuthConfiguration,
10
+ OAuthConfiguration,
11
+ UserManagedOAuthConfiguration,
12
+ } from "./capabilities/oauth.js";
13
+ export { oauth } from "./capabilities/oauth.js";
8
14
  export type {
9
15
  SyncConfiguration,
10
16
  SyncExecutionResult,