@notionhq/apps 0.0.32 → 0.0.34

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 (54) hide show
  1. package/README.md +59 -5
  2. package/dist/configured-events.d.ts +45 -0
  3. package/dist/configured-events.d.ts.map +1 -0
  4. package/dist/configured-events.js +38 -0
  5. package/dist/configured-events.test.d.ts +2 -0
  6. package/dist/configured-events.test.d.ts.map +1 -0
  7. package/dist/custom-block.d.ts +1 -1
  8. package/dist/events-types.test.d.ts +2 -0
  9. package/dist/events-types.test.d.ts.map +1 -0
  10. package/dist/{triggers.d.ts → events.d.ts} +1 -1
  11. package/dist/events.d.ts.map +1 -0
  12. package/dist/{triggers.generated.d.ts → events.generated.d.ts} +20 -38
  13. package/dist/events.generated.d.ts.map +1 -0
  14. package/dist/{triggers.generated.js → events.generated.js} +9 -35
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -0
  18. package/dist/notion-as-code/custom-agent.d.ts +3 -48
  19. package/dist/notion-as-code/custom-agent.d.ts.map +1 -1
  20. package/dist/notion-as-code/database.d.ts +11 -0
  21. package/dist/notion-as-code/database.d.ts.map +1 -1
  22. package/dist/notion-as-code/database.js +12 -0
  23. package/dist/notion-as-code/index.d.ts +1 -1
  24. package/dist/notion-as-code/index.d.ts.map +1 -1
  25. package/dist/notion-as-code/recurrence.d.ts +49 -0
  26. package/dist/notion-as-code/recurrence.d.ts.map +1 -0
  27. package/dist/notion-as-code/recurrence.js +0 -0
  28. package/dist/workflow.d.ts +4 -4
  29. package/dist/workflow.d.ts.map +1 -1
  30. package/dist/workflow.js +2 -2
  31. package/package.json +7 -7
  32. package/skills/connections/SKILL.md +3 -3
  33. package/skills/notion-as-code/SKILL.md +5 -0
  34. package/skills/workflow/SKILL.md +29 -5
  35. package/src/cli/build.test.ts +30 -0
  36. package/src/configured-events.test.ts +90 -0
  37. package/src/configured-events.ts +101 -0
  38. package/src/connections.ts +1 -1
  39. package/src/events-types.test.ts +110 -0
  40. package/src/{triggers.generated.ts → events.generated.ts} +21 -55
  41. package/src/index.ts +1 -0
  42. package/src/notion-as-code/custom-agent.ts +15 -61
  43. package/src/notion-as-code/database.ts +27 -0
  44. package/src/notion-as-code/index.ts +2 -0
  45. package/src/notion-as-code/recurrence.ts +58 -0
  46. package/src/workflow-access-types.test.ts +4 -4
  47. package/src/workflow-connections-types.test.ts +7 -7
  48. package/src/workflow-types.test.ts +23 -23
  49. package/src/workflow.test.ts +39 -39
  50. package/src/workflow.ts +7 -7
  51. package/dist/triggers.d.ts.map +0 -1
  52. package/dist/triggers.generated.d.ts.map +0 -1
  53. /package/dist/{triggers.js → events.js} +0 -0
  54. /package/src/{triggers.ts → events.ts} +0 -0
@@ -0,0 +1,110 @@
1
+ import { resolve } from "node:path";
2
+ import ts from "typescript";
3
+ import { expect, it } from "vitest";
4
+
5
+ it("checks property references and schedule variants in user code", () => {
6
+ const cases = [
7
+ {
8
+ name: "property",
9
+ valid: true,
10
+ expression:
11
+ "events.notionPageUpdated({ dataSource: tasks.dataSource, properties: [tasks.dataSource.properties.Status] })",
12
+ },
13
+ {
14
+ name: "content",
15
+ valid: true,
16
+ expression:
17
+ "events.notionPageUpdated({ dataSource: tasks.dataSource, includePageContent: true })",
18
+ },
19
+ {
20
+ name: "typo",
21
+ valid: false,
22
+ expression:
23
+ "events.notionPageUpdated({ dataSource: tasks.dataSource, properties: [tasks.dataSource.properties.Statuz] })",
24
+ },
25
+ {
26
+ name: "string",
27
+ valid: false,
28
+ expression:
29
+ 'events.notionPageUpdated({ dataSource: tasks.dataSource, properties: ["Status"] })',
30
+ },
31
+ {
32
+ name: "other_source",
33
+ valid: false,
34
+ expression:
35
+ "events.notionPageUpdated({ dataSource: tasks.dataSource, properties: [other.dataSource.properties.Name] })",
36
+ },
37
+ {
38
+ name: "unsupported_property",
39
+ valid: false,
40
+ expression:
41
+ "events.notionPageUpdated({ dataSource: tasks.dataSource, properties: [tasks.dataSource.properties.Files] })",
42
+ },
43
+ {
44
+ name: "empty",
45
+ valid: false,
46
+ expression:
47
+ "events.notionPageUpdated({ dataSource: tasks.dataSource, properties: [] })",
48
+ },
49
+ {
50
+ name: "no_watch",
51
+ valid: false,
52
+ expression: "events.notionPageUpdated({ dataSource: tasks.dataSource })",
53
+ },
54
+ {
55
+ name: "weekly",
56
+ valid: true,
57
+ expression:
58
+ 'events.scheduled({ frequency: "week", interval: 1, weekdays: { MO: true }, start: "2026-09-23", timeZone: "UTC" })',
59
+ },
60
+ {
61
+ name: "no_weekday",
62
+ valid: false,
63
+ expression:
64
+ 'events.scheduled({ frequency: "week", interval: 1, weekdays: {}, start: "2026-09-23", timeZone: "UTC" })',
65
+ },
66
+ ];
67
+ const fixtures = new Map(
68
+ cases.map((testCase) => [
69
+ resolve("src", `__events_${testCase.name}.ts`),
70
+ `
71
+ import { database, events } from "./index.js";
72
+ const tasks = database("tasks", { name: "Tasks", dataSourceResourceId: "tasks-source", schema: {
73
+ Name: { type: "title", resourceId: "name" }, Status: { type: "select", resourceId: "status", options: [] }, Files: { type: "file", resourceId: "files" }
74
+ } });
75
+ const other = database("other", { name: "Other", dataSourceResourceId: "other-source", schema: {
76
+ Name: { type: "title", resourceId: "other-name" }
77
+ } });
78
+ ${testCase.expression};
79
+ `,
80
+ ]),
81
+ );
82
+ const config = ts.readConfigFile(resolve("tsconfig.json"), ts.sys.readFile);
83
+ const parsed = ts.parseJsonConfigFileContent(config.config, ts.sys, process.cwd());
84
+ const host = ts.createCompilerHost(parsed.options);
85
+ const getSourceFile = host.getSourceFile.bind(host);
86
+ host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
87
+ const fixture = fixtures.get(fileName);
88
+ return fixture === undefined
89
+ ? getSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile)
90
+ : ts.createSourceFile(fileName, fixture, languageVersion, true);
91
+ };
92
+ const program = ts.createProgram(
93
+ [...fixtures.keys()],
94
+ { ...parsed.options, noEmit: true },
95
+ host,
96
+ );
97
+ const diagnostics = ts.getPreEmitDiagnostics(program);
98
+ expect(
99
+ diagnostics.filter(
100
+ (diagnostic) => !diagnostic.file || !fixtures.has(diagnostic.file.fileName),
101
+ ),
102
+ ).toEqual([]);
103
+ for (const testCase of cases) {
104
+ const errors = diagnostics.filter(
105
+ (diagnostic) =>
106
+ diagnostic.file?.fileName === resolve("src", `__events_${testCase.name}.ts`),
107
+ );
108
+ expect(errors.length === 0, testCase.name).toBe(testCase.valid);
109
+ }
110
+ });
@@ -1,7 +1,12 @@
1
- // Generated by scripts/generate-triggers.ts — do not edit by hand.
1
+ // Generated by scripts/generate-events.ts — do not edit by hand.
2
2
  // Regenerate with: pnpm run generate
3
3
 
4
4
  import type { WorkflowConnectionDeclarations, WorkflowConnectionKeys } from "./connections.js";
5
+ import { scheduled, notionPageCreated, notionPageUpdated } from "./configured-events.js";
6
+ import type { NotionPageCreatedTrigger, NotionPageUpdatedTrigger, PageUpdatedOptions, RecurrenceTrigger } from "./configured-events.js";
7
+ import type { DataSourceHandle } from "./notion-as-code/database.js";
8
+ import type { NotionAsCodeSchema } from "./notion-as-code/intents.js";
9
+ import type { RecurrenceSchedule } from "./notion-as-code/recurrence.js";
5
10
 
6
11
  import type {
7
12
  CalendarEventCanceledEvent,
@@ -25,7 +30,7 @@ import type {
25
30
  SlackMessageEvent,
26
31
  SlackReactionAddedEvent,
27
32
  WebhookEvent,
28
- } from "./triggers.js";
33
+ } from "./events.js";
29
34
 
30
35
  export type {
31
36
  Actor,
@@ -72,7 +77,10 @@ export type {
72
77
  VendorActor,
73
78
  VendorExtensions,
74
79
  WebhookEvent,
75
- } from "./triggers.js";
80
+ } from "./events.js";
81
+
82
+ export type { NotionPageCreatedTrigger, NotionPageUpdatedTrigger, PageUpdatedOptions, RecurrenceTrigger } from "./configured-events.js";
83
+ export type { RecurrenceSchedule } from "./notion-as-code/recurrence.js";
76
84
 
77
85
  /** Triggers immediately after a new message is posted in Slack (includes new threads and replies) */
78
86
  export type SlackMessageTrigger<TKey extends string = string> = {
@@ -144,16 +152,6 @@ export type CalendarEventCanceledTrigger<TKey extends string = string> = {
144
152
  connectionKey?: TKey;
145
153
  };
146
154
 
147
- /** A page has been added to a database. */
148
- export type NotionPageCreatedTrigger = {
149
- type: "notion.page.created";
150
- };
151
-
152
- /** A page was updated. */
153
- export type NotionPageUpdatedTrigger = {
154
- type: "notion.page.updated";
155
- };
156
-
157
155
  /** A page was deleted. */
158
156
  export type NotionPageDeletedTrigger = {
159
157
  type: "notion.page.deleted";
@@ -196,13 +194,8 @@ export type GoogleDriveOauthFilesChangedTrigger<TKey extends string = string> =
196
194
  connectionKey?: TKey;
197
195
  };
198
196
 
199
- /** A recurring schedule fired. */
200
- export type RecurrenceTrigger = {
201
- type: "recurrence";
202
- };
203
-
204
197
  /** Creators for each event that can trigger a workflow. */
205
- export const triggers = {
198
+ export const events = {
206
199
  /**
207
200
  * Declare that a workflow can run on `slack.message` events.
208
201
  *
@@ -323,27 +316,9 @@ export const triggers = {
323
316
  };
324
317
  },
325
318
 
326
- /**
327
- * Declare that a workflow can run on `notion.page.created` events.
328
- *
329
- * A page has been added to a database.
330
- */
331
- notionPageCreated(): NotionPageCreatedTrigger {
332
- return {
333
- type: "notion.page.created",
334
- };
335
- },
319
+ notionPageCreated,
336
320
 
337
- /**
338
- * Declare that a workflow can run on `notion.page.updated` events.
339
- *
340
- * A page was updated.
341
- */
342
- notionPageUpdated(): NotionPageUpdatedTrigger {
343
- return {
344
- type: "notion.page.updated",
345
- };
346
- },
321
+ notionPageUpdated,
347
322
 
348
323
  /**
349
324
  * Declare that a workflow can run on `notion.page.deleted` events.
@@ -434,20 +409,11 @@ export const triggers = {
434
409
  };
435
410
  },
436
411
 
437
- /**
438
- * Declare that a workflow can run on `recurrence` events.
439
- *
440
- * A recurring schedule fired.
441
- */
442
- scheduled(): RecurrenceTrigger {
443
- return {
444
- type: "recurrence",
445
- };
446
- },
412
+ scheduled,
447
413
  } as const;
448
414
 
449
415
  /** Trigger creators restricted to the workflow's declared provider keys. */
450
- export type WorkflowTriggerCreators<TConnections extends WorkflowConnectionDeclarations> = {
416
+ export type WorkflowEventCreators<TConnections extends WorkflowConnectionDeclarations> = {
451
417
  slackMessage(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "slack"> }): SlackMessageTrigger<WorkflowConnectionKeys<TConnections, "slack">>;
452
418
  slackReactionAdded(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "slack"> }): SlackReactionAddedTrigger<WorkflowConnectionKeys<TConnections, "slack">>;
453
419
  slackAppMention(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "slack"> }): SlackAppMentionTrigger<WorkflowConnectionKeys<TConnections, "slack">>;
@@ -458,8 +424,8 @@ export type WorkflowTriggerCreators<TConnections extends WorkflowConnectionDecla
458
424
  calendarEventCreated(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "calendar"> }): CalendarEventCreatedTrigger<WorkflowConnectionKeys<TConnections, "calendar">>;
459
425
  calendarEventUpdated(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "calendar"> }): CalendarEventUpdatedTrigger<WorkflowConnectionKeys<TConnections, "calendar">>;
460
426
  calendarEventCanceled(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "calendar"> }): CalendarEventCanceledTrigger<WorkflowConnectionKeys<TConnections, "calendar">>;
461
- notionPageCreated(): NotionPageCreatedTrigger;
462
- notionPageUpdated(): NotionPageUpdatedTrigger;
427
+ notionPageCreated(options?: { dataSource: DataSourceHandle }): NotionPageCreatedTrigger;
428
+ notionPageUpdated<const Schema extends NotionAsCodeSchema>(options?: PageUpdatedOptions<Schema>): NotionPageUpdatedTrigger;
463
429
  notionPageDeleted(): NotionPageDeletedTrigger;
464
430
  notionMeetingNoteSummaryCompleted(): NotionMeetingNoteSummaryCompletedTrigger;
465
431
  notionCommentAdded(): NotionCommentAddedTrigger;
@@ -468,7 +434,7 @@ export type WorkflowTriggerCreators<TConnections extends WorkflowConnectionDecla
468
434
  notionDatabaseAgentUpdated(): NotionDatabaseAgentUpdatedTrigger;
469
435
  webhook(): WebhookTrigger;
470
436
  googleDriveOauthFilesChanged(options?: { connectionKey: WorkflowConnectionKeys<TConnections, "googleDriveOauth"> }): GoogleDriveOauthFilesChangedTrigger<WorkflowConnectionKeys<TConnections, "googleDriveOauth">>;
471
- scheduled(): RecurrenceTrigger;
437
+ scheduled(options?: RecurrenceSchedule): RecurrenceTrigger;
472
438
  };
473
439
 
474
440
  /** Triggers whose connection keys belong to the declared provider. */
@@ -496,8 +462,8 @@ export type WorkflowTriggerForConnections<TConnections extends WorkflowConnectio
496
462
  | RecurrenceTrigger;
497
463
 
498
464
  /** @internal */
499
- export function createWorkflowTriggers<TConnections extends WorkflowConnectionDeclarations>(): WorkflowTriggerCreators<TConnections> {
500
- return triggers;
465
+ export function createWorkflowEvents<TConnections extends WorkflowConnectionDeclarations>(): WorkflowEventCreators<TConnections> {
466
+ return events;
501
467
  }
502
468
 
503
469
  /** Event that can trigger a workflow. */
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { events } from "./events.generated.js";
1
2
  export { customBlock, type CustomBlockHandle } from "./custom-block.js";
2
3
  export { customAgent } from "./notion-as-code/custom-agent.js";
3
4
  export { database } from "./notion-as-code/database.js";
@@ -3,67 +3,21 @@ import type { CustomAgentIntent, NotionAsCodeIcon, ResourceId } from "./intents.
3
3
  import { recordIntent } from "./recorder.js";
4
4
  import { assertUserResourceId } from "./resource.js";
5
5
 
6
- type RecurrenceWeekday = "MO" | "TU" | "WE" | "TH" | "FR" | "SA" | "SU";
7
-
8
- /** A nonempty selection of weekdays for a weekly recurrence. */
9
- export type RecurrenceWeekdays = {
10
- [Day in RecurrenceWeekday]?: true;
11
- } & {
12
- [Day in RecurrenceWeekday]: Required<Pick<Record<RecurrenceWeekday, true>, Day>>;
13
- }[RecurrenceWeekday];
14
-
15
- export type MonthlyWeekdayOccurrence = "1st" | "2nd" | "3rd" | "4th" | "last";
16
-
17
- export type MonthlyRecurrenceRestriction =
18
- | { type: "day_of_month"; day: number }
19
- | {
20
- type: "weekday_of_month";
21
- weekday: RecurrenceWeekday;
22
- occurrence: MonthlyWeekdayOccurrence;
23
- };
24
-
25
- export type RecurrenceScheduleEnd =
26
- | { type: "date"; endsAt: string }
27
- | { type: "occurrences"; count: number };
28
-
29
- type RecurrenceScheduleBase = {
30
- interval: number;
31
- start: string;
32
- timeZone: string;
33
- end?: RecurrenceScheduleEnd;
34
- };
35
-
36
- export type HourlyRecurrenceSchedule = RecurrenceScheduleBase & {
37
- frequency: "hour";
38
- };
39
-
40
- export type DailyRecurrenceSchedule = RecurrenceScheduleBase & {
41
- frequency: "day";
42
- };
43
-
44
- export type WeeklyRecurrenceSchedule = RecurrenceScheduleBase & {
45
- frequency: "week";
46
- weekdays: RecurrenceWeekdays;
47
- };
48
-
49
- export type MonthlyRecurrenceSchedule = RecurrenceScheduleBase & {
50
- frequency: "month";
51
- monthlyRestriction: MonthlyRecurrenceRestriction;
52
- };
53
-
54
- export type YearlyRecurrenceSchedule = RecurrenceScheduleBase & {
55
- frequency: "year";
56
- };
57
-
58
- export type CustomAgentRecurrenceSchedule = (
59
- | HourlyRecurrenceSchedule
60
- | DailyRecurrenceSchedule
61
- | WeeklyRecurrenceSchedule
62
- | MonthlyRecurrenceSchedule
63
- | YearlyRecurrenceSchedule
64
- ) & {
65
- type: "recurrence";
66
- };
6
+ import type { RecurrenceSchedule } from "./recurrence.js";
7
+ export type {
8
+ RecurrenceWeekdays,
9
+ MonthlyWeekdayOccurrence,
10
+ MonthlyRecurrenceRestriction,
11
+ RecurrenceScheduleEnd,
12
+ HourlyRecurrenceSchedule,
13
+ DailyRecurrenceSchedule,
14
+ WeeklyRecurrenceSchedule,
15
+ MonthlyRecurrenceSchedule,
16
+ YearlyRecurrenceSchedule,
17
+ RecurrenceSchedule,
18
+ } from "./recurrence.js";
19
+
20
+ export type CustomAgentRecurrenceSchedule = RecurrenceSchedule & { type: "recurrence" };
67
21
 
68
22
  export type CustomAgentTriggerBase = {
69
23
  resourceId: ResourceId;
@@ -118,6 +118,20 @@ export type ChildDatabaseArgs<
118
118
  | ChildMultiSourceDatabaseArgs<DataSources>
119
119
  | Omit<ViewOnlyDatabaseArgs, "parent">;
120
120
 
121
+ export type PropertyHandle<
122
+ Property extends NotionAsCodeSchema[string] = NotionAsCodeSchema[string],
123
+ > = {
124
+ readonly resourceType: "property";
125
+ readonly resourceId: Property["resourceId"];
126
+ readonly dataSourceResourceId: string;
127
+ readonly name: string;
128
+ readonly propertyType: Property["type"];
129
+ };
130
+
131
+ export type DataSourceProperties<Schema extends NotionAsCodeSchema> = {
132
+ readonly [Name in keyof Schema]: PropertyHandle<Schema[Name]>;
133
+ };
134
+
121
135
  /** A source handle retains its keyed authoring schema for sync inference. */
122
136
  export type DataSourceHandle<Schema extends NotionAsCodeSchema = NotionAsCodeSchema> = {
123
137
  readonly resourceType: "dataSource";
@@ -125,6 +139,7 @@ export type DataSourceHandle<Schema extends NotionAsCodeSchema = NotionAsCodeSch
125
139
  readonly name: string;
126
140
  readonly description?: string;
127
141
  readonly schema: Schema;
142
+ readonly properties: DataSourceProperties<Schema>;
128
143
  readonly database: Database<AppsSchemaForSchema<Schema>>;
129
144
  addPage: (args: ChildPageArgs) => PageHandle;
130
145
  };
@@ -501,6 +516,7 @@ function createDataSourceHandle(
501
516
  schema: NotionAsCodeSchema,
502
517
  databaseDescription: string | undefined,
503
518
  ): DataSourceHandle {
519
+ const propertyEntries: Array<[string, PropertyHandle]> = [];
504
520
  const propertyResourceIds = new Set<string>();
505
521
  const propertyNames = new Set<string>();
506
522
  for (const property of dataSource.properties) {
@@ -517,6 +533,16 @@ function createDataSourceHandle(
517
533
  }
518
534
  propertyResourceIds.add(property.resourceId);
519
535
  propertyNames.add(property.name);
536
+ propertyEntries.push([
537
+ property.name,
538
+ {
539
+ resourceType: "property",
540
+ resourceId: property.resourceId,
541
+ dataSourceResourceId: dataSource.resourceId,
542
+ name: property.name,
543
+ propertyType: property.type,
544
+ },
545
+ ]);
520
546
  }
521
547
  const description = dataSource.description ?? databaseDescription;
522
548
 
@@ -526,6 +552,7 @@ function createDataSourceHandle(
526
552
  name: dataSource.name,
527
553
  ...(description === undefined ? {} : { description }),
528
554
  schema,
555
+ properties: Object.fromEntries(propertyEntries),
529
556
  database: createAppsDatabase(dataSource.resourceId, dataSource),
530
557
  addPage(pageArgs) {
531
558
  return createPage(pageArgs, { type: "resourceId", resourceId: dataSource.resourceId });
@@ -62,6 +62,8 @@ export type {
62
62
  ChildSingleSourceDatabaseArgs,
63
63
  DataSourceArgs,
64
64
  DataSourceHandle,
65
+ DataSourceProperties,
66
+ PropertyHandle,
65
67
  DataSourceMap,
66
68
  DatabaseArgs,
67
69
  DatabaseHandle,
@@ -0,0 +1,58 @@
1
+ type RecurrenceWeekday = "MO" | "TU" | "WE" | "TH" | "FR" | "SA" | "SU";
2
+
3
+ /** A nonempty selection of weekdays for a weekly recurrence. */
4
+ export type RecurrenceWeekdays = {
5
+ [Day in RecurrenceWeekday]?: true;
6
+ } & {
7
+ [Day in RecurrenceWeekday]: Required<Pick<Record<RecurrenceWeekday, true>, Day>>;
8
+ }[RecurrenceWeekday];
9
+
10
+ export type MonthlyWeekdayOccurrence = "1st" | "2nd" | "3rd" | "4th" | "last";
11
+
12
+ export type MonthlyRecurrenceRestriction =
13
+ | { type: "day_of_month"; day: number }
14
+ | {
15
+ type: "weekday_of_month";
16
+ weekday: RecurrenceWeekday;
17
+ occurrence: MonthlyWeekdayOccurrence;
18
+ };
19
+
20
+ export type RecurrenceScheduleEnd =
21
+ | { type: "date"; endsAt: string }
22
+ | { type: "occurrences"; count: number };
23
+
24
+ type RecurrenceScheduleBase = {
25
+ interval: number;
26
+ start: string;
27
+ timeZone: string;
28
+ end?: RecurrenceScheduleEnd;
29
+ };
30
+
31
+ export type HourlyRecurrenceSchedule = RecurrenceScheduleBase & {
32
+ frequency: "hour";
33
+ };
34
+
35
+ export type DailyRecurrenceSchedule = RecurrenceScheduleBase & {
36
+ frequency: "day";
37
+ };
38
+
39
+ export type WeeklyRecurrenceSchedule = RecurrenceScheduleBase & {
40
+ frequency: "week";
41
+ weekdays: RecurrenceWeekdays;
42
+ };
43
+
44
+ export type MonthlyRecurrenceSchedule = RecurrenceScheduleBase & {
45
+ frequency: "month";
46
+ monthlyRestriction: MonthlyRecurrenceRestriction;
47
+ };
48
+
49
+ export type YearlyRecurrenceSchedule = RecurrenceScheduleBase & {
50
+ frequency: "year";
51
+ };
52
+
53
+ export type RecurrenceSchedule =
54
+ | HourlyRecurrenceSchedule
55
+ | DailyRecurrenceSchedule
56
+ | WeeklyRecurrenceSchedule
57
+ | MonthlyRecurrenceSchedule
58
+ | YearlyRecurrenceSchedule;
@@ -3,7 +3,7 @@ import { expectTypeOf, it } from "vitest";
3
3
  import { customAgent } from "./notion-as-code/custom-agent.js";
4
4
  import { database } from "./notion-as-code/database.js";
5
5
  import { page } from "./notion-as-code/page.js";
6
- import { triggers } from "./triggers.generated.js";
6
+ import { events } from "./events.generated.js";
7
7
  import { access, workflow } from "./workflow.js";
8
8
 
9
9
  it("infers access aliases and rejects resource-specific levels", () => {
@@ -26,7 +26,7 @@ it("infers access aliases and rejects resource-specific levels", () => {
26
26
  workflow({
27
27
  name: "Access types",
28
28
  description: "Checks access types",
29
- triggers: [triggers.notionPageCreated()],
29
+ triggers: [events.notionPageCreated()],
30
30
  access: {
31
31
  home: access.view(home),
32
32
  singleDatabase: access.edit(singleDatabase),
@@ -54,7 +54,7 @@ it("infers access aliases and rejects resource-specific levels", () => {
54
54
  workflow({
55
55
  name: "Agent access types",
56
56
  description: "Checks custom agent access types",
57
- triggers: [triggers.notionPageCreated()],
57
+ triggers: [events.notionPageCreated()],
58
58
  // @ts-expect-error Custom agents only support the call level.
59
59
  access: { agent: { resource: agent, level: "view" } },
60
60
  handler: () => {},
@@ -63,7 +63,7 @@ it("infers access aliases and rejects resource-specific levels", () => {
63
63
  workflow({
64
64
  name: "Page access types",
65
65
  description: "Checks page access types",
66
- triggers: [triggers.notionPageCreated()],
66
+ triggers: [events.notionPageCreated()],
67
67
  // @ts-expect-error Pages do not support the custom-agent call level.
68
68
  access: { home: { resource: home, level: "call" } },
69
69
  handler: () => {},
@@ -1,5 +1,5 @@
1
1
  import { expectTypeOf, it } from "vitest";
2
- import { triggers } from "./triggers.generated.js";
2
+ import { events } from "./events.generated.js";
3
3
  import { connections, workflow, type WorkflowConnectionDeclarations } from "./workflow.js";
4
4
 
5
5
  it("infers only the declared provider clients", () => {
@@ -7,7 +7,7 @@ it("infers only the declared provider clients", () => {
7
7
  name: "Mail",
8
8
  description: "Read the configured mailbox",
9
9
  connections: { inbox: connections.mail() },
10
- triggers: ({ triggers }) => [triggers.mailEmailReceived({ connectionKey: "inbox" })],
10
+ triggers: ({ events }) => [events.mailEmailReceived({ connectionKey: "inbox" })],
11
11
  handler(_event, context) {
12
12
  expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"inbox">();
13
13
  expectTypeOf(context.connections.inbox.searchEmails).toBeFunction();
@@ -19,7 +19,7 @@ it("infers only the declared provider clients", () => {
19
19
  workflow({
20
20
  name: "Calendar",
21
21
  description: "Calendar only",
22
- triggers: [triggers.notionPageCreated()],
22
+ triggers: [events.notionPageCreated()],
23
23
  connections: { work: connections.calendar() },
24
24
  handler(_event, context) {
25
25
  expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"work">();
@@ -37,7 +37,7 @@ it("infers only the declared provider clients", () => {
37
37
  workflow({
38
38
  name: "Multiple providers",
39
39
  description: "Preserves clients in a separately declared object",
40
- triggers: [triggers.notionPageCreated()],
40
+ triggers: [events.notionPageCreated()],
41
41
  connections: requirements,
42
42
  handler(_event, context) {
43
43
  expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<
@@ -51,7 +51,7 @@ it("exposes no providers for omitted or empty connections", () => {
51
51
  workflow({
52
52
  name: "No connections",
53
53
  description: "Omitted",
54
- triggers: [triggers.notionPageCreated()],
54
+ triggers: [events.notionPageCreated()],
55
55
  handler(_event, context) {
56
56
  expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<never>();
57
57
  },
@@ -59,7 +59,7 @@ it("exposes no providers for omitted or empty connections", () => {
59
59
  workflow({
60
60
  name: "No connections",
61
61
  description: "Empty",
62
- triggers: [triggers.notionPageCreated()],
62
+ triggers: [events.notionPageCreated()],
63
63
  connections: {},
64
64
  handler(_event, context) {
65
65
  expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<never>();
@@ -72,7 +72,7 @@ it("preserves literal declarations checked with satisfies", () => {
72
72
  workflow({
73
73
  name: "Slack",
74
74
  description: "Slack only",
75
- triggers: [triggers.notionPageCreated()],
75
+ triggers: [events.notionPageCreated()],
76
76
  connections: requirements,
77
77
  handler(_event, context) {
78
78
  expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<"support">();