@notionhq/apps 0.0.15 → 0.0.17
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/AGENTS.md +13 -0
- package/README.md +69 -2
- package/dist/connections.d.ts +39 -11
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +85 -21
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/notion-as-code/database.d.ts +26 -3
- package/dist/notion-as-code/database.d.ts.map +1 -1
- package/dist/notion-as-code/database.js +27 -0
- package/dist/notion-as-code/handles.d.ts +2 -0
- package/dist/notion-as-code/handles.d.ts.map +1 -1
- package/dist/notion-as-code/handles.js +2 -0
- package/dist/notion-as-code/index.d.ts +4 -1
- package/dist/notion-as-code/index.d.ts.map +1 -1
- package/dist/notion-as-code/intents.d.ts +2 -1
- package/dist/notion-as-code/intents.d.ts.map +1 -1
- package/dist/notion-as-code/page.d.ts +3 -3
- package/dist/notion-as-code/page.d.ts.map +1 -1
- package/dist/notion-as-code/page.js +2 -7
- package/dist/notion-as-code/teamspace.d.ts +3 -3
- package/dist/notion-as-code/teamspace.d.ts.map +1 -1
- package/dist/notion-as-code/teamspace.js +2 -7
- package/dist/notion-as-code/view.d.ts +12 -0
- package/dist/notion-as-code/view.d.ts.map +1 -0
- package/dist/notion-as-code/view.js +13 -0
- package/dist/notion-as-code/views-types.test.d.ts +2 -0
- package/dist/notion-as-code/views-types.test.d.ts.map +1 -0
- package/dist/notion-as-code/views.d.ts +469 -0
- package/dist/notion-as-code/views.d.ts.map +1 -0
- package/dist/notion-as-code/views.js +0 -0
- package/dist/oauth.d.ts +11 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +26 -0
- package/dist/providers.generated.d.ts +26 -86
- package/dist/providers.generated.d.ts.map +1 -1
- package/dist/providers.generated.js +54 -66
- package/dist/triggers.generated.d.ts +3 -3
- package/dist/triggers.generated.d.ts.map +1 -1
- package/dist/workflow.d.ts +8 -8
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +12 -6
- package/docs/CONNECTIONS.md +70 -22
- package/package.json +3 -1
- package/skills/connections/SKILL.md +85 -0
- package/skills/custom-blocks/SKILL.md +45 -0
- package/skills/notion-as-code/SKILL.md +195 -0
- package/skills/sync/SKILL.md +98 -0
- package/skills/workflow/SKILL.md +123 -0
- package/src/cli/build.test.ts +95 -3
- package/src/connections.test.ts +205 -41
- package/src/connections.ts +144 -38
- package/src/index.ts +1 -0
- package/src/notion-as-code/database.ts +75 -5
- package/src/notion-as-code/handles.ts +2 -0
- package/src/notion-as-code/index.ts +59 -0
- package/src/notion-as-code/intents.ts +2 -2
- package/src/notion-as-code/page.ts +3 -11
- package/src/notion-as-code/teamspace.ts +3 -11
- package/src/notion-as-code/view.ts +23 -0
- package/src/notion-as-code/views-types.test.ts +59 -0
- package/src/notion-as-code/views.ts +554 -0
- package/src/oauth.ts +40 -0
- package/src/providers.generated.ts +68 -163
- package/src/triggers.generated.ts +4 -4
- package/src/workflow-connections-types.test.ts +16 -10
- package/src/workflow-types.test.ts +88 -16
- package/src/workflow.test.ts +45 -17
- package/src/workflow.ts +31 -17
|
@@ -27,181 +27,86 @@ export const connections = {
|
|
|
27
27
|
outlook,
|
|
28
28
|
salesforce,
|
|
29
29
|
}
|
|
30
|
-
export type
|
|
31
|
-
calendar
|
|
32
|
-
slack
|
|
33
|
-
googleDriveOauth
|
|
34
|
-
discord
|
|
35
|
-
cursor
|
|
36
|
-
box
|
|
37
|
-
confluence
|
|
38
|
-
gmail
|
|
39
|
-
googleCalendar
|
|
40
|
-
googleDrive
|
|
41
|
-
outlook
|
|
42
|
-
salesforce
|
|
30
|
+
export type ConnectionClients = {
|
|
31
|
+
calendar: CalendarConnectionClient
|
|
32
|
+
slack: SlackConnectionClient
|
|
33
|
+
googleDriveOauth: GoogleDriveOauthConnectionClient
|
|
34
|
+
discord: DiscordConnectionClient
|
|
35
|
+
cursor: CursorConnectionClient
|
|
36
|
+
box: BoxConnectionClient
|
|
37
|
+
confluence: ConfluenceConnectionClient
|
|
38
|
+
gmail: GmailConnectionClient
|
|
39
|
+
googleCalendar: GoogleCalendarConnectionClient
|
|
40
|
+
googleDrive: GoogleDriveConnectionClient
|
|
41
|
+
outlook: OutlookConnectionClient
|
|
42
|
+
salesforce: SalesforceConnectionClient
|
|
43
43
|
}
|
|
44
|
-
export function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return new SlackConnectionClient(invoker
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return new
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return new
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
},
|
|
76
|
-
googleCalendar(key = "googleCalendar"): GoogleCalendarConnectionClient {
|
|
77
|
-
return new GoogleCalendarConnectionClient(invoker("googleCalendar", key))
|
|
78
|
-
},
|
|
79
|
-
googleDrive(key = "googleDrive"): GoogleDriveConnectionClient {
|
|
80
|
-
return new GoogleDriveConnectionClient(invoker("googleDrive", key))
|
|
81
|
-
},
|
|
82
|
-
outlook(key = "outlook"): OutlookConnectionClient {
|
|
83
|
-
return new OutlookConnectionClient(invoker("outlook", key))
|
|
84
|
-
},
|
|
85
|
-
salesforce(key = "salesforce"): SalesforceConnectionClient {
|
|
86
|
-
return new SalesforceConnectionClient(invoker("salesforce", key))
|
|
87
|
-
},
|
|
44
|
+
export function createConnectionClient(
|
|
45
|
+
provider: string,
|
|
46
|
+
invoker: ConnectionActionInvoker,
|
|
47
|
+
): ConnectionClients[keyof ConnectionClients] {
|
|
48
|
+
switch (provider) {
|
|
49
|
+
case "calendar":
|
|
50
|
+
return new CalendarConnectionClient(invoker)
|
|
51
|
+
case "slack":
|
|
52
|
+
return new SlackConnectionClient(invoker)
|
|
53
|
+
case "googleDriveOauth":
|
|
54
|
+
return new GoogleDriveOauthConnectionClient(invoker)
|
|
55
|
+
case "discord":
|
|
56
|
+
return new DiscordConnectionClient(invoker)
|
|
57
|
+
case "cursor":
|
|
58
|
+
return new CursorConnectionClient(invoker)
|
|
59
|
+
case "box":
|
|
60
|
+
return new BoxConnectionClient(invoker)
|
|
61
|
+
case "confluence":
|
|
62
|
+
return new ConfluenceConnectionClient(invoker)
|
|
63
|
+
case "gmail":
|
|
64
|
+
return new GmailConnectionClient(invoker)
|
|
65
|
+
case "googleCalendar":
|
|
66
|
+
return new GoogleCalendarConnectionClient(invoker)
|
|
67
|
+
case "googleDrive":
|
|
68
|
+
return new GoogleDriveConnectionClient(invoker)
|
|
69
|
+
case "outlook":
|
|
70
|
+
return new OutlookConnectionClient(invoker)
|
|
71
|
+
case "salesforce":
|
|
72
|
+
return new SalesforceConnectionClient(invoker)
|
|
73
|
+
default:
|
|
74
|
+
throw new Error("Unsupported connection provider: " + provider)
|
|
88
75
|
}
|
|
89
76
|
}
|
|
90
|
-
function calendar(
|
|
91
|
-
|
|
92
|
-
}): WorkflowConnection<"calendar", "calendar">
|
|
93
|
-
function calendar<const TKey extends string>(options: {
|
|
94
|
-
key: TKey
|
|
95
|
-
}): WorkflowConnection<"calendar", TKey>
|
|
96
|
-
function calendar(
|
|
97
|
-
options: { key?: string } = {},
|
|
98
|
-
): WorkflowConnection<"calendar"> {
|
|
99
|
-
return { type: "calendar", ...options }
|
|
77
|
+
function calendar(): WorkflowConnection<"calendar"> {
|
|
78
|
+
return { type: "calendar" }
|
|
100
79
|
}
|
|
101
|
-
function slack(
|
|
102
|
-
|
|
103
|
-
key: TKey
|
|
104
|
-
}): WorkflowConnection<"slack", TKey>
|
|
105
|
-
function slack(options: { key?: string } = {}): WorkflowConnection<"slack"> {
|
|
106
|
-
return { type: "slack", ...options }
|
|
80
|
+
function slack(): WorkflowConnection<"slack"> {
|
|
81
|
+
return { type: "slack" }
|
|
107
82
|
}
|
|
108
|
-
function googleDriveOauth(
|
|
109
|
-
|
|
110
|
-
}): WorkflowConnection<"googleDriveOauth", "googleDriveOauth">
|
|
111
|
-
function googleDriveOauth<const TKey extends string>(options: {
|
|
112
|
-
key: TKey
|
|
113
|
-
}): WorkflowConnection<"googleDriveOauth", TKey>
|
|
114
|
-
function googleDriveOauth(
|
|
115
|
-
options: { key?: string } = {},
|
|
116
|
-
): WorkflowConnection<"googleDriveOauth"> {
|
|
117
|
-
return { type: "googleDriveOauth", ...options }
|
|
83
|
+
function googleDriveOauth(): WorkflowConnection<"googleDriveOauth"> {
|
|
84
|
+
return { type: "googleDriveOauth" }
|
|
118
85
|
}
|
|
119
|
-
function discord(
|
|
120
|
-
|
|
121
|
-
}): WorkflowConnection<"discord", "discord">
|
|
122
|
-
function discord<const TKey extends string>(options: {
|
|
123
|
-
key: TKey
|
|
124
|
-
}): WorkflowConnection<"discord", TKey>
|
|
125
|
-
function discord(
|
|
126
|
-
options: { key?: string } = {},
|
|
127
|
-
): WorkflowConnection<"discord"> {
|
|
128
|
-
return { type: "discord", ...options }
|
|
86
|
+
function discord(): WorkflowConnection<"discord"> {
|
|
87
|
+
return { type: "discord" }
|
|
129
88
|
}
|
|
130
|
-
function cursor(
|
|
131
|
-
|
|
132
|
-
}): WorkflowConnection<"cursor", "cursor">
|
|
133
|
-
function cursor<const TKey extends string>(options: {
|
|
134
|
-
key: TKey
|
|
135
|
-
}): WorkflowConnection<"cursor", TKey>
|
|
136
|
-
function cursor(options: { key?: string } = {}): WorkflowConnection<"cursor"> {
|
|
137
|
-
return { type: "cursor", ...options }
|
|
89
|
+
function cursor(): WorkflowConnection<"cursor"> {
|
|
90
|
+
return { type: "cursor" }
|
|
138
91
|
}
|
|
139
|
-
function box(
|
|
140
|
-
|
|
141
|
-
key: TKey
|
|
142
|
-
}): WorkflowConnection<"box", TKey>
|
|
143
|
-
function box(options: { key?: string } = {}): WorkflowConnection<"box"> {
|
|
144
|
-
return { type: "box", ...options }
|
|
92
|
+
function box(): WorkflowConnection<"box"> {
|
|
93
|
+
return { type: "box" }
|
|
145
94
|
}
|
|
146
|
-
function confluence(
|
|
147
|
-
|
|
148
|
-
}): WorkflowConnection<"confluence", "confluence">
|
|
149
|
-
function confluence<const TKey extends string>(options: {
|
|
150
|
-
key: TKey
|
|
151
|
-
}): WorkflowConnection<"confluence", TKey>
|
|
152
|
-
function confluence(
|
|
153
|
-
options: { key?: string } = {},
|
|
154
|
-
): WorkflowConnection<"confluence"> {
|
|
155
|
-
return { type: "confluence", ...options }
|
|
95
|
+
function confluence(): WorkflowConnection<"confluence"> {
|
|
96
|
+
return { type: "confluence" }
|
|
156
97
|
}
|
|
157
|
-
function gmail(
|
|
158
|
-
|
|
159
|
-
key: TKey
|
|
160
|
-
}): WorkflowConnection<"gmail", TKey>
|
|
161
|
-
function gmail(options: { key?: string } = {}): WorkflowConnection<"gmail"> {
|
|
162
|
-
return { type: "gmail", ...options }
|
|
98
|
+
function gmail(): WorkflowConnection<"gmail"> {
|
|
99
|
+
return { type: "gmail" }
|
|
163
100
|
}
|
|
164
|
-
function googleCalendar(
|
|
165
|
-
|
|
166
|
-
}): WorkflowConnection<"googleCalendar", "googleCalendar">
|
|
167
|
-
function googleCalendar<const TKey extends string>(options: {
|
|
168
|
-
key: TKey
|
|
169
|
-
}): WorkflowConnection<"googleCalendar", TKey>
|
|
170
|
-
function googleCalendar(
|
|
171
|
-
options: { key?: string } = {},
|
|
172
|
-
): WorkflowConnection<"googleCalendar"> {
|
|
173
|
-
return { type: "googleCalendar", ...options }
|
|
101
|
+
function googleCalendar(): WorkflowConnection<"googleCalendar"> {
|
|
102
|
+
return { type: "googleCalendar" }
|
|
174
103
|
}
|
|
175
|
-
function googleDrive(
|
|
176
|
-
|
|
177
|
-
}): WorkflowConnection<"googleDrive", "googleDrive">
|
|
178
|
-
function googleDrive<const TKey extends string>(options: {
|
|
179
|
-
key: TKey
|
|
180
|
-
}): WorkflowConnection<"googleDrive", TKey>
|
|
181
|
-
function googleDrive(
|
|
182
|
-
options: { key?: string } = {},
|
|
183
|
-
): WorkflowConnection<"googleDrive"> {
|
|
184
|
-
return { type: "googleDrive", ...options }
|
|
104
|
+
function googleDrive(): WorkflowConnection<"googleDrive"> {
|
|
105
|
+
return { type: "googleDrive" }
|
|
185
106
|
}
|
|
186
|
-
function outlook(
|
|
187
|
-
|
|
188
|
-
}): WorkflowConnection<"outlook", "outlook">
|
|
189
|
-
function outlook<const TKey extends string>(options: {
|
|
190
|
-
key: TKey
|
|
191
|
-
}): WorkflowConnection<"outlook", TKey>
|
|
192
|
-
function outlook(
|
|
193
|
-
options: { key?: string } = {},
|
|
194
|
-
): WorkflowConnection<"outlook"> {
|
|
195
|
-
return { type: "outlook", ...options }
|
|
107
|
+
function outlook(): WorkflowConnection<"outlook"> {
|
|
108
|
+
return { type: "outlook" }
|
|
196
109
|
}
|
|
197
|
-
function salesforce(
|
|
198
|
-
|
|
199
|
-
}): WorkflowConnection<"salesforce", "salesforce">
|
|
200
|
-
function salesforce<const TKey extends string>(options: {
|
|
201
|
-
key: TKey
|
|
202
|
-
}): WorkflowConnection<"salesforce", TKey>
|
|
203
|
-
function salesforce(
|
|
204
|
-
options: { key?: string } = {},
|
|
205
|
-
): WorkflowConnection<"salesforce"> {
|
|
206
|
-
return { type: "salesforce", ...options }
|
|
110
|
+
function salesforce(): WorkflowConnection<"salesforce"> {
|
|
111
|
+
return { type: "salesforce" }
|
|
207
112
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by scripts/generate-triggers.ts — do not edit by hand.
|
|
2
2
|
// Regenerate with: pnpm run generate
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { WorkflowConnectionDeclarations, WorkflowConnectionKeys } from "./connections.js";
|
|
5
5
|
|
|
6
6
|
import type {
|
|
7
7
|
CalendarEventCanceledEvent,
|
|
@@ -438,7 +438,7 @@ export const triggers = {
|
|
|
438
438
|
} as const;
|
|
439
439
|
|
|
440
440
|
/** Trigger creators restricted to the workflow's declared provider keys. */
|
|
441
|
-
export type WorkflowTriggerCreators<TConnections extends
|
|
441
|
+
export type WorkflowTriggerCreators<TConnections extends WorkflowConnectionDeclarations> = {
|
|
442
442
|
slackMessage(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "slack"> }): SlackMessageTrigger<WorkflowConnectionKeys<TConnections, "slack">>;
|
|
443
443
|
slackReactionAdded(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "slack"> }): SlackReactionAddedTrigger<WorkflowConnectionKeys<TConnections, "slack">>;
|
|
444
444
|
slackAppMention(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "slack"> }): SlackAppMentionTrigger<WorkflowConnectionKeys<TConnections, "slack">>;
|
|
@@ -463,7 +463,7 @@ export type WorkflowTriggerCreators<TConnections extends readonly WorkflowConnec
|
|
|
463
463
|
};
|
|
464
464
|
|
|
465
465
|
/** Triggers whose connection keys belong to the declared provider. */
|
|
466
|
-
export type WorkflowTriggerForConnections<TConnections extends
|
|
466
|
+
export type WorkflowTriggerForConnections<TConnections extends WorkflowConnectionDeclarations> =
|
|
467
467
|
| SlackMessageTrigger<WorkflowConnectionKeys<TConnections, "slack">>
|
|
468
468
|
| SlackReactionAddedTrigger<WorkflowConnectionKeys<TConnections, "slack">>
|
|
469
469
|
| SlackAppMentionTrigger<WorkflowConnectionKeys<TConnections, "slack">>
|
|
@@ -487,7 +487,7 @@ export type WorkflowTriggerForConnections<TConnections extends readonly Workflow
|
|
|
487
487
|
| RecurrenceTrigger;
|
|
488
488
|
|
|
489
489
|
/** @internal */
|
|
490
|
-
export function createWorkflowTriggers<TConnections extends
|
|
490
|
+
export function createWorkflowTriggers<TConnections extends WorkflowConnectionDeclarations>(): WorkflowTriggerCreators<TConnections> {
|
|
491
491
|
return triggers;
|
|
492
492
|
}
|
|
493
493
|
|
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
import { expectTypeOf, it } from "vitest";
|
|
2
2
|
import { triggers } from "./triggers.generated.js";
|
|
3
|
-
import { connections, workflow, type
|
|
3
|
+
import { connections, workflow, type WorkflowConnectionDeclarations } from "./workflow.js";
|
|
4
4
|
|
|
5
5
|
it("infers only the declared provider clients", () => {
|
|
6
6
|
workflow({
|
|
7
7
|
name: "Calendar",
|
|
8
8
|
description: "Calendar only",
|
|
9
9
|
triggers: [triggers.notionPageCreated()],
|
|
10
|
-
connections:
|
|
10
|
+
connections: { work: connections.calendar() },
|
|
11
11
|
handler(_event, context) {
|
|
12
|
-
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"
|
|
13
|
-
expectTypeOf(context.connections.
|
|
12
|
+
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"work">();
|
|
13
|
+
expectTypeOf(context.connections.work.listCalendars).toBeFunction();
|
|
14
14
|
},
|
|
15
15
|
});
|
|
16
|
-
const requirements =
|
|
16
|
+
const requirements = {
|
|
17
|
+
calendar: connections.calendar(),
|
|
18
|
+
support: connections.slack(),
|
|
19
|
+
team: connections.slack(),
|
|
20
|
+
};
|
|
17
21
|
workflow({
|
|
18
22
|
name: "Multiple providers",
|
|
19
|
-
description: "Preserves
|
|
23
|
+
description: "Preserves clients in a separately declared object",
|
|
20
24
|
triggers: [triggers.notionPageCreated()],
|
|
21
25
|
connections: requirements,
|
|
22
26
|
handler(_event, context) {
|
|
23
|
-
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<
|
|
27
|
+
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<
|
|
28
|
+
"calendar" | "support" | "team"
|
|
29
|
+
>();
|
|
24
30
|
},
|
|
25
31
|
});
|
|
26
32
|
});
|
|
@@ -38,7 +44,7 @@ it("exposes no providers for omitted or empty connections", () => {
|
|
|
38
44
|
name: "No connections",
|
|
39
45
|
description: "Empty",
|
|
40
46
|
triggers: [triggers.notionPageCreated()],
|
|
41
|
-
connections:
|
|
47
|
+
connections: {},
|
|
42
48
|
handler(_event, context) {
|
|
43
49
|
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<never>();
|
|
44
50
|
},
|
|
@@ -46,14 +52,14 @@ it("exposes no providers for omitted or empty connections", () => {
|
|
|
46
52
|
});
|
|
47
53
|
|
|
48
54
|
it("preserves literal declarations checked with satisfies", () => {
|
|
49
|
-
const requirements =
|
|
55
|
+
const requirements = { support: connections.slack() } satisfies WorkflowConnectionDeclarations;
|
|
50
56
|
workflow({
|
|
51
57
|
name: "Slack",
|
|
52
58
|
description: "Slack only",
|
|
53
59
|
triggers: [triggers.notionPageCreated()],
|
|
54
60
|
connections: requirements,
|
|
55
61
|
handler(_event, context) {
|
|
56
|
-
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"
|
|
62
|
+
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"support">();
|
|
57
63
|
},
|
|
58
64
|
});
|
|
59
65
|
});
|
|
@@ -7,44 +7,44 @@ it("checks provider keys on callback arguments and returned triggers", () => {
|
|
|
7
7
|
{
|
|
8
8
|
name: "valid",
|
|
9
9
|
valid: true,
|
|
10
|
-
connections:
|
|
10
|
+
connections: "{ support: connections.slack(), calendar: connections.calendar() }",
|
|
11
11
|
trigger:
|
|
12
12
|
'triggers.slackMessage({ connectionKey: "support" }), triggers.calendarEventCreated({ connectionKey: "calendar" })',
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
name: "default",
|
|
16
16
|
valid: true,
|
|
17
|
-
connections: "
|
|
17
|
+
connections: "{ slack: connections.slack() }",
|
|
18
18
|
trigger: 'triggers.slackMessage({ connectionKey: "slack" })',
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
name: "unbound",
|
|
22
22
|
valid: true,
|
|
23
|
-
connections: "
|
|
23
|
+
connections: "{}",
|
|
24
24
|
trigger: "triggers.slackMessage(), triggers.notionPageCreated()",
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
name: "global_valid",
|
|
28
28
|
valid: true,
|
|
29
|
-
connections:
|
|
29
|
+
connections: "{ support: connections.slack() }",
|
|
30
30
|
trigger: 'globalTriggers.slackMessage({ connectionKey: "support" })',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
name: "undeclared",
|
|
34
34
|
valid: false,
|
|
35
|
-
connections:
|
|
35
|
+
connections: "{ support: connections.slack() }",
|
|
36
36
|
trigger: 'triggers.slackMessage({ connectionKey: "typo" })',
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
name: "wrong_provider",
|
|
40
40
|
valid: false,
|
|
41
|
-
connections:
|
|
41
|
+
connections: "{ support: connections.calendar() }",
|
|
42
42
|
trigger: 'triggers.slackMessage({ connectionKey: "support" })',
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
name: "custom_not_default",
|
|
46
46
|
valid: false,
|
|
47
|
-
connections:
|
|
47
|
+
connections: "{ support: connections.slack() }",
|
|
48
48
|
trigger: 'triggers.slackMessage({ connectionKey: "slack" })',
|
|
49
49
|
},
|
|
50
50
|
{
|
|
@@ -56,51 +56,123 @@ it("checks provider keys on callback arguments and returned triggers", () => {
|
|
|
56
56
|
{
|
|
57
57
|
name: "global_invalid",
|
|
58
58
|
valid: false,
|
|
59
|
-
connections:
|
|
59
|
+
connections: "{ support: connections.calendar() }",
|
|
60
60
|
trigger: 'globalTriggers.slackMessage({ connectionKey: "support" })',
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
name: "literal_invalid",
|
|
64
64
|
valid: false,
|
|
65
|
-
connections:
|
|
65
|
+
connections: "{ support: connections.calendar() }",
|
|
66
66
|
trigger: '{ type: "slack.message", connectionKey: "support" }',
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
|
-
name: "
|
|
69
|
+
name: "old_key_option",
|
|
70
70
|
valid: false,
|
|
71
|
-
connections: '
|
|
71
|
+
connections: '{ support: connections.slack({ key: "support" }) }',
|
|
72
72
|
trigger: 'triggers.slackMessage({ connectionKey: "support" })',
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
name: "literal_default",
|
|
76
76
|
valid: true,
|
|
77
|
-
connections: '
|
|
77
|
+
connections: '{ slack: { type: "slack" } }',
|
|
78
78
|
trigger: 'triggers.slackMessage({ connectionKey: "slack" })',
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
name: "saved",
|
|
82
82
|
valid: true,
|
|
83
|
-
connections: "
|
|
83
|
+
connections: "{ support }",
|
|
84
84
|
trigger: 'triggers.slackMessage({ connectionKey: "support" })',
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
name: "saved_invalid",
|
|
88
88
|
valid: false,
|
|
89
|
-
connections: "
|
|
89
|
+
connections: "{ support }",
|
|
90
90
|
trigger: 'triggers.slackMessage({ connectionKey: "slack" })',
|
|
91
91
|
},
|
|
92
|
+
{
|
|
93
|
+
name: "old_array",
|
|
94
|
+
valid: false,
|
|
95
|
+
connections: "[connections.slack()]",
|
|
96
|
+
trigger: "triggers.slackMessage()",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "two_slack",
|
|
100
|
+
valid: true,
|
|
101
|
+
connections: "{ support: connections.slack(), team: connections.slack() }",
|
|
102
|
+
trigger: 'triggers.slackMessage({ connectionKey: "team" })',
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
{
|
|
106
|
+
name: "keyed_clients",
|
|
107
|
+
valid: true,
|
|
108
|
+
connections:
|
|
109
|
+
"{ support: connections.slack(), team: connections.slack(), work: connections.calendar() }",
|
|
110
|
+
trigger: "triggers.notionPageCreated()",
|
|
111
|
+
handler:
|
|
112
|
+
'(_event, ctx) => { ctx.connections.support.findUserByEmail({ email: "a@example.com" }); ctx.connections.team.findUserByEmail({ email: "b@example.com" }); ctx.connections.work.listCalendars({}); }',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "wrong_client_method",
|
|
116
|
+
valid: false,
|
|
117
|
+
connections: "{ support: connections.slack() }",
|
|
118
|
+
trigger: "triggers.notionPageCreated()",
|
|
119
|
+
handler: "(_event, ctx) => { ctx.connections.support.listCalendars({}); }",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "undeclared_client",
|
|
123
|
+
valid: false,
|
|
124
|
+
connections: "{ support: connections.slack() }",
|
|
125
|
+
trigger: "triggers.notionPageCreated()",
|
|
126
|
+
handler:
|
|
127
|
+
'(_event, ctx) => { ctx.connections.slack.findUserByEmail({ email: "a@example.com" }); }',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "old_provider_call",
|
|
131
|
+
valid: false,
|
|
132
|
+
connections: "{ support: connections.slack() }",
|
|
133
|
+
trigger: "triggers.notionPageCreated()",
|
|
134
|
+
handler: '(_event, ctx) => { ctx.connections.support("support"); }',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "oauth_keyed_client",
|
|
138
|
+
valid: true,
|
|
139
|
+
connections: "{ github: connections.oauth(oauthConfig), support: connections.slack() }",
|
|
140
|
+
trigger: 'triggers.slackMessage({ connectionKey: "support" })',
|
|
141
|
+
handler:
|
|
142
|
+
"async (_event, ctx) => { const token: string = await ctx.connections.github.accessToken(); void token; }",
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: "oauth_wrong_trigger",
|
|
146
|
+
valid: false,
|
|
147
|
+
connections: "{ github: connections.oauth(oauthConfig) }",
|
|
148
|
+
trigger: 'triggers.slackMessage({ connectionKey: "github" })',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: "oauth_old_key_option",
|
|
152
|
+
valid: false,
|
|
153
|
+
connections: '{ github: connections.oauth({ ...oauthConfig, key: "github" }) }',
|
|
154
|
+
trigger: "triggers.notionPageCreated()",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "oauth_old_provider_call",
|
|
158
|
+
valid: false,
|
|
159
|
+
connections: "{ github: connections.oauth(oauthConfig) }",
|
|
160
|
+
trigger: "triggers.notionPageCreated()",
|
|
161
|
+
handler: '(_event, ctx) => { ctx.connections.oauth("github"); }',
|
|
162
|
+
},
|
|
92
163
|
];
|
|
93
164
|
const fixtures = new Map(
|
|
94
165
|
cases.map((testCase) => [
|
|
95
166
|
resolve("src", `__workflow_types_${testCase.name}.ts`),
|
|
96
167
|
`import { connections, workflow } from "./workflow.js";
|
|
97
168
|
import { triggers as globalTriggers } from "./triggers.generated.js";
|
|
98
|
-
const support = connections.slack(
|
|
169
|
+
const support = connections.slack();
|
|
170
|
+
const oauthConfig = { authorizationEndpoint: "https://example.com/authorize", tokenEndpoint: "https://example.com/token", clientId: "client", clientSecretEnv: "CLIENT_SECRET", scope: "read" };
|
|
99
171
|
workflow({
|
|
100
172
|
name: "Type check", description: "Type check",
|
|
101
173
|
${testCase.connections === undefined ? "" : `connections: ${testCase.connections},`}
|
|
102
174
|
triggers: ({ triggers }) => [${testCase.trigger}],
|
|
103
|
-
handler: () => {},
|
|
175
|
+
handler: ${testCase.handler ?? "() => {}"},
|
|
104
176
|
});`,
|
|
105
177
|
]),
|
|
106
178
|
);
|
package/src/workflow.test.ts
CHANGED
|
@@ -37,8 +37,8 @@ afterEach(async () => {
|
|
|
37
37
|
|
|
38
38
|
const event = { type: "notion.page.created" } as NotionPageCreatedEvent;
|
|
39
39
|
|
|
40
|
-
async function createWorkflowContext(): Promise<WorkflowContext<
|
|
41
|
-
let context: WorkflowContext<
|
|
40
|
+
async function createWorkflowContext(): Promise<WorkflowContext<Record<never, never>>> {
|
|
41
|
+
let context: WorkflowContext<Record<never, never>> | undefined;
|
|
42
42
|
const definition = workflow({
|
|
43
43
|
name: "Test workflow",
|
|
44
44
|
description: "Captures its workflow context",
|
|
@@ -743,23 +743,54 @@ describe("workflow", () => {
|
|
|
743
743
|
name: "Schedule Follow-up",
|
|
744
744
|
description: "Schedules a follow-up after a page is created",
|
|
745
745
|
triggers: [triggers.notionPageCreated()],
|
|
746
|
-
connections:
|
|
746
|
+
connections: { calendar: connections.calendar() },
|
|
747
747
|
handler: () => {},
|
|
748
748
|
});
|
|
749
749
|
|
|
750
|
-
expect(definition.config.connections).toEqual([{ type: "calendar" }]);
|
|
750
|
+
expect(definition.config.connections).toEqual([{ type: "calendar", key: "calendar" }]);
|
|
751
751
|
});
|
|
752
752
|
|
|
753
|
-
it("
|
|
753
|
+
it("keeps declaration keys stable after the input object changes", async () => {
|
|
754
|
+
const declarations = { support: connections.slack() };
|
|
755
|
+
const seen: string[][] = [];
|
|
756
|
+
const definition = workflow({
|
|
757
|
+
name: "Snapshot connections",
|
|
758
|
+
description: "Captures declared keys",
|
|
759
|
+
connections: declarations,
|
|
760
|
+
triggers: [triggers.notionPageCreated()],
|
|
761
|
+
handler(_event, context) {
|
|
762
|
+
seen.push(Object.keys(context.connections));
|
|
763
|
+
},
|
|
764
|
+
});
|
|
765
|
+
Object.assign(declarations, { support: connections.calendar(), team: connections.slack() });
|
|
766
|
+
expect(definition.config.connections).toEqual([{ type: "slack", key: "support" }]);
|
|
767
|
+
await definition.handler(event, { concreteOutput: true });
|
|
768
|
+
expect(seen).toEqual([["support"]]);
|
|
769
|
+
});
|
|
770
|
+
it("rejects inherited declaration objects before cloning", () => {
|
|
771
|
+
const declarations = { support: connections.slack() };
|
|
772
|
+
Object.setPrototypeOf(declarations, { extra: connections.calendar() });
|
|
773
|
+
expect(() =>
|
|
774
|
+
workflow({
|
|
775
|
+
name: "Inherited keys",
|
|
776
|
+
description: "Reject prototype declarations",
|
|
777
|
+
connections: declarations,
|
|
778
|
+
triggers: [triggers.notionPageCreated()],
|
|
779
|
+
handler() {},
|
|
780
|
+
}),
|
|
781
|
+
).toThrow("only own");
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
it("rejects invalid connection property names", () => {
|
|
754
785
|
expect(() =>
|
|
755
786
|
workflow({
|
|
756
787
|
name: "Schedule Follow-up",
|
|
757
788
|
description: "Schedules a follow-up after a page is created",
|
|
758
789
|
triggers: [triggers.notionPageCreated()],
|
|
759
|
-
connections:
|
|
790
|
+
connections: { "bad/key": connections.calendar() },
|
|
760
791
|
handler: () => {},
|
|
761
792
|
}),
|
|
762
|
-
).toThrowError("
|
|
793
|
+
).toThrowError("Invalid workflow connection key: bad/key");
|
|
763
794
|
});
|
|
764
795
|
|
|
765
796
|
it("writes a success envelope after the handler runs", async () => {
|
|
@@ -839,7 +870,7 @@ describe("connection-bound triggers", () => {
|
|
|
839
870
|
const definition = workflow({
|
|
840
871
|
name: "Typed triggers",
|
|
841
872
|
description: "Uses only declared provider keys",
|
|
842
|
-
connections:
|
|
873
|
+
connections: { support: connections.slack(), calendar: connections.calendar() },
|
|
843
874
|
triggers: ({ triggers }) => {
|
|
844
875
|
calls += 1;
|
|
845
876
|
expectTypeOf(triggers.slackMessage)
|
|
@@ -861,7 +892,7 @@ describe("connection-bound triggers", () => {
|
|
|
861
892
|
"slack.message" | "calendar.event.created"
|
|
862
893
|
>();
|
|
863
894
|
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<
|
|
864
|
-
"
|
|
895
|
+
"support" | "calendar"
|
|
865
896
|
>();
|
|
866
897
|
},
|
|
867
898
|
});
|
|
@@ -876,7 +907,7 @@ describe("connection-bound triggers", () => {
|
|
|
876
907
|
const definition = workflow({
|
|
877
908
|
name: "Support",
|
|
878
909
|
description: "Watch support messages",
|
|
879
|
-
connections:
|
|
910
|
+
connections: { support: connections.slack() },
|
|
880
911
|
triggers: [triggers.slackMessage({ connectionKey: "support" })],
|
|
881
912
|
handler(event) {
|
|
882
913
|
expectTypeOf(event.type).toEqualTypeOf<"slack.message">();
|
|
@@ -887,9 +918,9 @@ describe("connection-bound triggers", () => {
|
|
|
887
918
|
]);
|
|
888
919
|
});
|
|
889
920
|
it.each([
|
|
890
|
-
{ requirements:
|
|
891
|
-
{ requirements:
|
|
892
|
-
{ requirements:
|
|
921
|
+
{ requirements: {} },
|
|
922
|
+
{ requirements: { support: connections.calendar() } },
|
|
923
|
+
{ requirements: { other: connections.slack() } },
|
|
893
924
|
])("rejects missing or incompatible declarations: %j", ({ requirements }) => {
|
|
894
925
|
expect(() =>
|
|
895
926
|
workflow({
|
|
@@ -905,10 +936,7 @@ describe("connection-bound triggers", () => {
|
|
|
905
936
|
const configuration = {
|
|
906
937
|
name: "Support",
|
|
907
938
|
description: "",
|
|
908
|
-
connections:
|
|
909
|
-
connections.slack({ key: "support" }),
|
|
910
|
-
connections.slack({ key: "internal" }),
|
|
911
|
-
],
|
|
939
|
+
connections: { support: connections.slack(), internal: connections.slack() },
|
|
912
940
|
handler() {},
|
|
913
941
|
};
|
|
914
942
|
expect(() =>
|