@project-ajax/sdk 0.0.64 → 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.
- package/dist/capabilities/oauth.d.ts +145 -0
- package/dist/capabilities/oauth.d.ts.map +1 -0
- package/dist/capabilities/oauth.js +53 -0
- package/dist/capabilities/oauth.test.d.ts +2 -0
- package/dist/capabilities/oauth.test.d.ts.map +1 -0
- package/dist/capabilities/sync.d.ts +13 -1
- package/dist/capabilities/sync.d.ts.map +1 -1
- package/dist/capabilities/sync.js +46 -2
- package/dist/error.d.ts +4 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +5 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/oauth.test.ts +51 -0
- package/src/capabilities/oauth.ts +181 -0
- package/src/capabilities/sync.ts +76 -2
- package/src/error.ts +7 -0
- package/src/index.ts +13 -1
- package/src/types.ts +27 -0
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.test.d.ts","sourceRoot":"","sources":["../../src/capabilities/oauth.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PropertyConfiguration, PropertySchema, Schema } from "../schema.js";
|
|
2
|
-
import type { Icon, PeopleValue, TextValue } from "../types.js";
|
|
2
|
+
import type { Icon, PeopleValue, Schedule, SyncSchedule, TextValue } from "../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Maps a property configuration to its corresponding value type.
|
|
5
5
|
*/
|
|
@@ -72,6 +72,17 @@ export type SyncConfiguration<PK extends string, S extends Schema<PK>, Context =
|
|
|
72
72
|
* @default false
|
|
73
73
|
*/
|
|
74
74
|
deleteUnreturnedPages?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* How often the sync should run.
|
|
77
|
+
* - "continuous": Run as frequently as the system allows (default)
|
|
78
|
+
* - Interval string: Run at specified intervals, e.g. "1h", "30m", "1d"
|
|
79
|
+
*
|
|
80
|
+
* Minimum interval: 1 minute ("1m")
|
|
81
|
+
* Maximum interval: 7 days ("7d")
|
|
82
|
+
*
|
|
83
|
+
* @default "continuous"
|
|
84
|
+
*/
|
|
85
|
+
schedule?: Schedule;
|
|
75
86
|
/**
|
|
76
87
|
* A function that fetches the data to sync from the third-party service.
|
|
77
88
|
*
|
|
@@ -108,6 +119,7 @@ export declare function sync<PK extends string, S extends Schema<PK>, Context =
|
|
|
108
119
|
primaryKeyProperty: PK;
|
|
109
120
|
schema: S;
|
|
110
121
|
deleteUnreturnedPages: boolean | undefined;
|
|
122
|
+
schedule: SyncSchedule;
|
|
111
123
|
};
|
|
112
124
|
handler(context?: Context): Promise<{
|
|
113
125
|
objects: SyncedObject<PK, PropertySchema<PK>>[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/capabilities/sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,qBAAqB,EACrB,cAAc,EACd,MAAM,EACN,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/capabilities/sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,qBAAqB,EACrB,cAAc,EACd,MAAM,EACN,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACX,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EAET,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,KAAK,iBAAiB,CAAC,CAAC,SAAS,qBAAqB,IAAI,CAAC,SAAS;IACnE,IAAI,EAAE,QAAQ,CAAC;CACf,GACE,WAAW,GACX,SAAS,CAAC;AAEb;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC,SAAS,cAAc,CAAC,EAAE,CAAC,IAAI;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE;SACV,QAAQ,IAAI,MAAM,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;KACrD,CAAC;IACF;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,OAAO,GAAG,OAAO,IAAI;IACvE;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAEhD;;;;OAIG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAC5B,EAAE,SAAS,MAAM,EACjB,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,EACpB,OAAO,GAAG,OAAO,IACd;IACH;;;;OAIG;IACH,kBAAkB,EAAE,EAAE,CAAC;IAEvB;;OAEG;IACH,MAAM,EAAE,CAAC,CAAC;IAEV;;;;;;;;OAQG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;;;;;;;;;;;OAaG;IACH,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,mBAAmB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,OAAO,GAAG,OAAO,IAAI;IACrE,kBAAkB,EAAE,EAAE,CAAC;IACvB,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAChD,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,IAAI,CACnB,EAAE,SAAS,MAAM,EACjB,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,EACpB,OAAO,GAAG,OAAO,EAChB,iBAAiB,EAAE,iBAAiB,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC;;;;;;;;sBAS5B,OAAO;;;;;EAkBhC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { ExecutionError } from "../error.js";
|
|
1
|
+
import { ExecutionError, unreachable } from "../error.js";
|
|
2
2
|
function sync(syncConfiguration) {
|
|
3
3
|
return {
|
|
4
4
|
_tag: "sync",
|
|
5
5
|
config: {
|
|
6
6
|
primaryKeyProperty: syncConfiguration.primaryKeyProperty,
|
|
7
7
|
schema: syncConfiguration.schema,
|
|
8
|
-
deleteUnreturnedPages: syncConfiguration.deleteUnreturnedPages
|
|
8
|
+
deleteUnreturnedPages: syncConfiguration.deleteUnreturnedPages,
|
|
9
|
+
schedule: parseSchedule(syncConfiguration.schedule)
|
|
9
10
|
},
|
|
10
11
|
async handler(context) {
|
|
11
12
|
const executionResult = await syncConfiguration.execute(context).catch((err) => {
|
|
@@ -23,6 +24,49 @@ function sync(syncConfiguration) {
|
|
|
23
24
|
}
|
|
24
25
|
};
|
|
25
26
|
}
|
|
27
|
+
const MS_PER_MINUTE = 60 * 1e3;
|
|
28
|
+
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
|
29
|
+
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
|
30
|
+
const MIN_INTERVAL_MS = MS_PER_MINUTE;
|
|
31
|
+
const MAX_INTERVAL_MS = 7 * MS_PER_DAY;
|
|
32
|
+
function parseSchedule(schedule) {
|
|
33
|
+
if (!schedule || schedule === "continuous") {
|
|
34
|
+
return { type: "continuous" };
|
|
35
|
+
}
|
|
36
|
+
const match = schedule.match(/^(\d+)(m|h|d)$/);
|
|
37
|
+
if (!match || !match[1] || !match[2]) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Invalid schedule format: "${schedule}". Use "continuous" or an interval like "30m", "1h", "1d".`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const value = parseInt(match[1], 10);
|
|
43
|
+
const unit = match[2];
|
|
44
|
+
let intervalMs;
|
|
45
|
+
switch (unit) {
|
|
46
|
+
case "m":
|
|
47
|
+
intervalMs = value * MS_PER_MINUTE;
|
|
48
|
+
break;
|
|
49
|
+
case "h":
|
|
50
|
+
intervalMs = value * MS_PER_HOUR;
|
|
51
|
+
break;
|
|
52
|
+
case "d":
|
|
53
|
+
intervalMs = value * MS_PER_DAY;
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
unreachable(unit);
|
|
57
|
+
}
|
|
58
|
+
if (intervalMs < MIN_INTERVAL_MS) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Schedule interval must be at least 1 minute. Got: "${schedule}"`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (intervalMs > MAX_INTERVAL_MS) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Schedule interval must be at most 7 days. Got: "${schedule}"`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return { type: "interval", intervalMs };
|
|
69
|
+
}
|
|
26
70
|
export {
|
|
27
71
|
sync
|
|
28
72
|
};
|
package/dist/error.d.ts
CHANGED
|
@@ -5,4 +5,8 @@ export declare class ExecutionError extends Error {
|
|
|
5
5
|
readonly cause: unknown;
|
|
6
6
|
constructor(cause: unknown);
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Helper for exhaustive switch statements. TypeScript will error if a case is not handled.
|
|
10
|
+
*/
|
|
11
|
+
export declare function unreachable(value: never): never;
|
|
8
12
|
//# sourceMappingURL=error.d.ts.map
|
package/dist/error.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBAEZ,KAAK,EAAE,OAAO;CAK1B"}
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACxC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBAEZ,KAAK,EAAE,OAAO;CAK1B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAE/C"}
|
package/dist/error.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
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";
|
|
7
|
-
export type { Icon, ImageIcon, NoticonColor, NoticonName } from "./types.js";
|
|
9
|
+
export type { Icon, ImageIcon, NoticonColor, NoticonName, Schedule, } from "./types.js";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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/dist/types.d.ts
CHANGED
|
@@ -130,4 +130,30 @@ export interface PersonReference {
|
|
|
130
130
|
*/
|
|
131
131
|
export type PeopleValue = PersonReference[];
|
|
132
132
|
export type { NoticonName } from "./icon-names.js";
|
|
133
|
+
/**
|
|
134
|
+
* Time units for schedule intervals.
|
|
135
|
+
* - "m": minutes
|
|
136
|
+
* - "h": hours
|
|
137
|
+
* - "d": days
|
|
138
|
+
*/
|
|
139
|
+
export type TimeUnit = "m" | "h" | "d";
|
|
140
|
+
/**
|
|
141
|
+
* A string representing an interval, e.g. "30m", "1h", "7d".
|
|
142
|
+
*/
|
|
143
|
+
export type IntervalString = `${number}${TimeUnit}`;
|
|
144
|
+
/**
|
|
145
|
+
* Schedule configuration for sync capabilities.
|
|
146
|
+
* - "continuous": Run as frequently as the system allows
|
|
147
|
+
* - IntervalString: Run at specified intervals, e.g. "30m", "1h", "1d"
|
|
148
|
+
*/
|
|
149
|
+
export type Schedule = "continuous" | IntervalString;
|
|
150
|
+
/**
|
|
151
|
+
* Normalized schedule representation stored in the backend.
|
|
152
|
+
*/
|
|
153
|
+
export type SyncSchedule = {
|
|
154
|
+
type: "continuous";
|
|
155
|
+
} | {
|
|
156
|
+
type: "interval";
|
|
157
|
+
intervalMs: number;
|
|
158
|
+
};
|
|
133
159
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -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/capabilities/sync.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import { ExecutionError } from "../error.js";
|
|
1
|
+
import { ExecutionError, unreachable } from "../error.js";
|
|
2
2
|
import type {
|
|
3
3
|
PropertyConfiguration,
|
|
4
4
|
PropertySchema,
|
|
5
5
|
Schema,
|
|
6
6
|
} from "../schema.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
Icon,
|
|
9
|
+
PeopleValue,
|
|
10
|
+
Schedule,
|
|
11
|
+
SyncSchedule,
|
|
12
|
+
TextValue,
|
|
13
|
+
TimeUnit,
|
|
14
|
+
} from "../types.js";
|
|
8
15
|
|
|
9
16
|
/**
|
|
10
17
|
* Maps a property configuration to its corresponding value type.
|
|
@@ -92,6 +99,18 @@ export type SyncConfiguration<
|
|
|
92
99
|
*/
|
|
93
100
|
deleteUnreturnedPages?: boolean;
|
|
94
101
|
|
|
102
|
+
/**
|
|
103
|
+
* How often the sync should run.
|
|
104
|
+
* - "continuous": Run as frequently as the system allows (default)
|
|
105
|
+
* - Interval string: Run at specified intervals, e.g. "1h", "30m", "1d"
|
|
106
|
+
*
|
|
107
|
+
* Minimum interval: 1 minute ("1m")
|
|
108
|
+
* Maximum interval: 7 days ("7d")
|
|
109
|
+
*
|
|
110
|
+
* @default "continuous"
|
|
111
|
+
*/
|
|
112
|
+
schedule?: Schedule;
|
|
113
|
+
|
|
95
114
|
/**
|
|
96
115
|
* A function that fetches the data to sync from the third-party service.
|
|
97
116
|
*
|
|
@@ -135,6 +154,7 @@ export function sync<
|
|
|
135
154
|
primaryKeyProperty: syncConfiguration.primaryKeyProperty,
|
|
136
155
|
schema: syncConfiguration.schema,
|
|
137
156
|
deleteUnreturnedPages: syncConfiguration.deleteUnreturnedPages,
|
|
157
|
+
schedule: parseSchedule(syncConfiguration.schedule),
|
|
138
158
|
},
|
|
139
159
|
async handler(context?: Context) {
|
|
140
160
|
const executionResult = await syncConfiguration
|
|
@@ -155,3 +175,57 @@ export function sync<
|
|
|
155
175
|
},
|
|
156
176
|
};
|
|
157
177
|
}
|
|
178
|
+
|
|
179
|
+
const MS_PER_MINUTE = 60 * 1000;
|
|
180
|
+
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
|
181
|
+
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
|
182
|
+
|
|
183
|
+
const MIN_INTERVAL_MS = MS_PER_MINUTE; // 1m
|
|
184
|
+
const MAX_INTERVAL_MS = 7 * MS_PER_DAY; // 7d
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Parses a user-friendly schedule string into the normalized backend format.
|
|
188
|
+
*/
|
|
189
|
+
function parseSchedule(schedule: Schedule | undefined): SyncSchedule {
|
|
190
|
+
if (!schedule || schedule === "continuous") {
|
|
191
|
+
return { type: "continuous" };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const match = schedule.match(/^(\d+)(m|h|d)$/);
|
|
195
|
+
if (!match || !match[1] || !match[2]) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`Invalid schedule format: "${schedule}". Use "continuous" or an interval like "30m", "1h", "1d".`,
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const value = parseInt(match[1], 10);
|
|
202
|
+
const unit = match[2] as TimeUnit;
|
|
203
|
+
|
|
204
|
+
let intervalMs: number;
|
|
205
|
+
switch (unit) {
|
|
206
|
+
case "m":
|
|
207
|
+
intervalMs = value * MS_PER_MINUTE;
|
|
208
|
+
break;
|
|
209
|
+
case "h":
|
|
210
|
+
intervalMs = value * MS_PER_HOUR;
|
|
211
|
+
break;
|
|
212
|
+
case "d":
|
|
213
|
+
intervalMs = value * MS_PER_DAY;
|
|
214
|
+
break;
|
|
215
|
+
default:
|
|
216
|
+
unreachable(unit);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (intervalMs < MIN_INTERVAL_MS) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
`Schedule interval must be at least 1 minute. Got: "${schedule}"`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (intervalMs > MAX_INTERVAL_MS) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
`Schedule interval must be at most 7 days. Got: "${schedule}"`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return { type: "interval", intervalMs };
|
|
231
|
+
}
|
package/src/error.ts
CHANGED
|
@@ -10,3 +10,10 @@ export class ExecutionError extends Error {
|
|
|
10
10
|
this.cause = cause;
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Helper for exhaustive switch statements. TypeScript will error if a case is not handled.
|
|
16
|
+
*/
|
|
17
|
+
export function unreachable(value: never): never {
|
|
18
|
+
throw new Error(`Unreachable: ${value}`);
|
|
19
|
+
}
|
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,
|
|
@@ -12,4 +18,10 @@ export type {
|
|
|
12
18
|
} from "./capabilities/sync.js";
|
|
13
19
|
export { sync } from "./capabilities/sync.js";
|
|
14
20
|
export { tool } from "./capabilities/tool.js";
|
|
15
|
-
export type {
|
|
21
|
+
export type {
|
|
22
|
+
Icon,
|
|
23
|
+
ImageIcon,
|
|
24
|
+
NoticonColor,
|
|
25
|
+
NoticonName,
|
|
26
|
+
Schedule,
|
|
27
|
+
} from "./types.js";
|
package/src/types.ts
CHANGED
|
@@ -187,3 +187,30 @@ export interface PersonReference {
|
|
|
187
187
|
export type PeopleValue = PersonReference[];
|
|
188
188
|
|
|
189
189
|
export type { NoticonName } from "./icon-names.js";
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Time units for schedule intervals.
|
|
193
|
+
* - "m": minutes
|
|
194
|
+
* - "h": hours
|
|
195
|
+
* - "d": days
|
|
196
|
+
*/
|
|
197
|
+
export type TimeUnit = "m" | "h" | "d";
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* A string representing an interval, e.g. "30m", "1h", "7d".
|
|
201
|
+
*/
|
|
202
|
+
export type IntervalString = `${number}${TimeUnit}`;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Schedule configuration for sync capabilities.
|
|
206
|
+
* - "continuous": Run as frequently as the system allows
|
|
207
|
+
* - IntervalString: Run at specified intervals, e.g. "30m", "1h", "1d"
|
|
208
|
+
*/
|
|
209
|
+
export type Schedule = "continuous" | IntervalString;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Normalized schedule representation stored in the backend.
|
|
213
|
+
*/
|
|
214
|
+
export type SyncSchedule =
|
|
215
|
+
| { type: "continuous" }
|
|
216
|
+
| { type: "interval"; intervalMs: number };
|