@notionhq/apps 0.0.9 → 0.0.11

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 (67) hide show
  1. package/dist/cli/build.d.ts +2 -2
  2. package/dist/cli/build.d.ts.map +1 -1
  3. package/dist/cli/build.js +44 -2
  4. package/dist/cli/codegen.d.ts +5 -0
  5. package/dist/cli/codegen.d.ts.map +1 -1
  6. package/dist/cli/codegen.js +15 -1
  7. package/dist/cli/emit-manifest.d.ts +3 -0
  8. package/dist/cli/emit-manifest.d.ts.map +1 -1
  9. package/dist/cli/emit-manifest.js +12 -1
  10. package/dist/notion-as-code/custom-agent.d.ts +18 -0
  11. package/dist/notion-as-code/custom-agent.d.ts.map +1 -0
  12. package/dist/notion-as-code/custom-agent.js +13 -0
  13. package/dist/notion-as-code/database.d.ts +44 -0
  14. package/dist/notion-as-code/database.d.ts.map +1 -0
  15. package/dist/notion-as-code/database.js +68 -0
  16. package/dist/notion-as-code/date.d.ts +9 -0
  17. package/dist/notion-as-code/date.d.ts.map +1 -0
  18. package/dist/notion-as-code/date.js +69 -0
  19. package/dist/notion-as-code/handles.d.ts +32 -0
  20. package/dist/notion-as-code/handles.d.ts.map +1 -0
  21. package/dist/notion-as-code/handles.js +34 -0
  22. package/dist/notion-as-code/index.d.ts +30 -0
  23. package/dist/notion-as-code/index.d.ts.map +1 -0
  24. package/dist/notion-as-code/index.js +8 -0
  25. package/dist/notion-as-code/intents.d.ts +115 -0
  26. package/dist/notion-as-code/intents.d.ts.map +1 -0
  27. package/dist/notion-as-code/intents.js +6 -0
  28. package/dist/notion-as-code/page.d.ts +22 -0
  29. package/dist/notion-as-code/page.d.ts.map +1 -0
  30. package/dist/notion-as-code/page.js +31 -0
  31. package/dist/notion-as-code/provisioning.d.ts +22 -0
  32. package/dist/notion-as-code/provisioning.d.ts.map +1 -0
  33. package/dist/notion-as-code/provisioning.js +25 -0
  34. package/dist/notion-as-code/recorder.d.ts +10 -0
  35. package/dist/notion-as-code/recorder.d.ts.map +1 -0
  36. package/dist/notion-as-code/recorder.js +21 -0
  37. package/dist/notion-as-code/resource.d.ts +6 -0
  38. package/dist/notion-as-code/resource.d.ts.map +1 -0
  39. package/dist/notion-as-code/resource.js +19 -0
  40. package/dist/notion-as-code/schema.d.ts +63 -0
  41. package/dist/notion-as-code/schema.d.ts.map +1 -0
  42. package/dist/notion-as-code/schema.js +94 -0
  43. package/dist/notion-as-code/teamspace.d.ts +18 -0
  44. package/dist/notion-as-code/teamspace.d.ts.map +1 -0
  45. package/dist/notion-as-code/teamspace.js +30 -0
  46. package/dist/sync.d.ts +15 -2
  47. package/dist/sync.d.ts.map +1 -1
  48. package/dist/sync.js +14 -3
  49. package/package.json +9 -1
  50. package/src/cli/build.test.ts +91 -1
  51. package/src/cli/build.ts +61 -6
  52. package/src/cli/codegen.ts +21 -0
  53. package/src/cli/discover.test.ts +6 -0
  54. package/src/cli/emit-manifest.ts +18 -0
  55. package/src/notion-as-code/custom-agent.ts +30 -0
  56. package/src/notion-as-code/database.ts +143 -0
  57. package/src/notion-as-code/date.ts +91 -0
  58. package/src/notion-as-code/handles.ts +36 -0
  59. package/src/notion-as-code/index.ts +16 -0
  60. package/src/notion-as-code/intents.ts +127 -0
  61. package/src/notion-as-code/page.ts +61 -0
  62. package/src/notion-as-code/provisioning.ts +50 -0
  63. package/src/notion-as-code/recorder.ts +26 -0
  64. package/src/notion-as-code/resource.ts +19 -0
  65. package/src/notion-as-code/schema.ts +149 -0
  66. package/src/notion-as-code/teamspace.ts +50 -0
  67. package/src/sync.ts +63 -5
@@ -0,0 +1,6 @@
1
+ const APPS_WORKSPACE_RESOURCE_ID = "__notion_apps_workspace__";
2
+ const APPS_RESERVED_RESOURCE_ID_PREFIX = "__notion_apps_";
3
+ export {
4
+ APPS_RESERVED_RESOURCE_ID_PREFIX,
5
+ APPS_WORKSPACE_RESOURCE_ID
6
+ };
@@ -0,0 +1,22 @@
1
+ import type { DataSourceDefinition, NotionAsCodeIcon, Parent, ResourceId } from "./intents.js";
2
+ import { type ChildDatabaseArgs, type DatabaseHandle } from "./database.js";
3
+ export type PageArgs = {
4
+ resourceId: ResourceId;
5
+ parent: Parent;
6
+ icon?: NotionAsCodeIcon;
7
+ cover?: unknown;
8
+ properties?: Record<string, unknown>;
9
+ content?: string;
10
+ fullWidth?: boolean;
11
+ };
12
+ export type ChildPageArgs = Omit<PageArgs, "parent">;
13
+ export type PageHandle = {
14
+ readonly resourceId: string;
15
+ addDatabase: <const DataSources extends readonly DataSourceDefinition[]>(args: ChildDatabaseArgs<DataSources>) => DatabaseHandle<DataSources>;
16
+ addPage: (args: ChildPageArgs) => PageHandle;
17
+ };
18
+ /** Declare a top-level page. */
19
+ export declare function page(args: PageArgs): PageHandle;
20
+ /** Record a page declaration beneath its parent resource. */
21
+ export declare function createPage(args: ChildPageArgs | PageArgs, parent: Parent): PageHandle;
22
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../src/notion-as-code/page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,oBAAoB,EACpB,gBAAgB,EAEhB,MAAM,EACN,UAAU,EACV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAY,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAItF,MAAM,MAAM,QAAQ,GAAG;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,gBAAgB,CAAC;IAExB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAErD,MAAM,MAAM,UAAU,GAAG;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,CAAC,KAAK,CAAC,WAAW,SAAS,SAAS,oBAAoB,EAAE,EACtE,IAAI,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAChC,cAAc,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,UAAU,CAAC;CAC7C,CAAC;AAEF,gCAAgC;AAChC,wBAAgB,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAG/C;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAoBrF"}
@@ -0,0 +1,31 @@
1
+ import { database } from "./database.js";
2
+ import { recordIntent } from "./recorder.js";
3
+ import { assertParent, assertUserResourceId } from "./resource.js";
4
+ function page(args) {
5
+ assertParent(args.parent);
6
+ return createPage(args, args.parent);
7
+ }
8
+ function createPage(args, parent) {
9
+ assertUserResourceId(args.resourceId);
10
+ recordIntent({
11
+ type: "page",
12
+ ...args,
13
+ parent
14
+ });
15
+ return {
16
+ resourceId: args.resourceId,
17
+ addDatabase(databaseArgs) {
18
+ return database({
19
+ ...databaseArgs,
20
+ parent: { type: "resourceId", resourceId: args.resourceId }
21
+ });
22
+ },
23
+ addPage(pageArgs) {
24
+ return createPage(pageArgs, { type: "resourceId", resourceId: args.resourceId });
25
+ }
26
+ };
27
+ }
28
+ export {
29
+ createPage,
30
+ page
31
+ };
@@ -0,0 +1,22 @@
1
+ import type { InfraAsCodeIntent } from "./intents.js";
2
+ export declare const APPS_PROVISIONING_SCHEMA = "notion:apps-provisioning:v1";
3
+ /** Provisioning intents recorded while evaluating the build-only metadata bundle. */
4
+ export type RecordedProvisioning = {
5
+ intents: InfraAsCodeIntent[];
6
+ };
7
+ /** Teamspaces are always created in the Apps workspace, so Apps supplies their parent. */
8
+ export type ProvisioningIntent = Omit<Extract<InfraAsCodeIntent, {
9
+ type: "teamspace";
10
+ }>, "parent"> | Exclude<InfraAsCodeIntent, {
11
+ type: "teamspace";
12
+ }>;
13
+ export type ProvisioningArtifact = {
14
+ $schema: typeof APPS_PROVISIONING_SCHEMA;
15
+ version: 1;
16
+ intents: readonly ProvisioningIntent[];
17
+ };
18
+ /** Convert recorded declarations into the server-facing provisioning artifact. */
19
+ export declare function createProvisioningArtifact(intents: readonly InfraAsCodeIntent[]): ProvisioningArtifact;
20
+ /** Check that a metadata bundle exported the recorder output. */
21
+ export declare function isRecordedProvisioning(value: unknown): value is RecordedProvisioning;
22
+ //# sourceMappingURL=provisioning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisioning.d.ts","sourceRoot":"","sources":["../../src/notion-as-code/provisioning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAEtE,qFAAqF;AACrF,MAAM,MAAM,oBAAoB,GAAG;IAClC,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC7B,CAAC;AAEF,0FAA0F;AAC1F,MAAM,MAAM,kBAAkB,GAC3B,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,EAAE,QAAQ,CAAC,GACjE,OAAO,CAAC,iBAAiB,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AAErD,MAAM,MAAM,oBAAoB,GAAG;IAClC,OAAO,EAAE,OAAO,wBAAwB,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACvC,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,0BAA0B,CACzC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GACnC,oBAAoB,CAgBtB;AAED,iEAAiE;AACjE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,oBAAoB,CAOpF"}
@@ -0,0 +1,25 @@
1
+ const APPS_PROVISIONING_SCHEMA = "notion:apps-provisioning:v1";
2
+ function createProvisioningArtifact(intents) {
3
+ const provisioningIntents = [];
4
+ for (const intent of intents) {
5
+ if (intent.type === "teamspace") {
6
+ const { parent: _parent, ...teamspace } = intent;
7
+ provisioningIntents.push(teamspace);
8
+ } else {
9
+ provisioningIntents.push(intent);
10
+ }
11
+ }
12
+ return {
13
+ $schema: APPS_PROVISIONING_SCHEMA,
14
+ version: 1,
15
+ intents: provisioningIntents
16
+ };
17
+ }
18
+ function isRecordedProvisioning(value) {
19
+ return typeof value === "object" && value !== null && "intents" in value && Array.isArray(value.intents);
20
+ }
21
+ export {
22
+ APPS_PROVISIONING_SCHEMA,
23
+ createProvisioningArtifact,
24
+ isRecordedProvisioning
25
+ };
@@ -0,0 +1,10 @@
1
+ /** Records Notion-as-Code declarations while the build-only metadata bundle evaluates. */
2
+ import type { InfraAsCodeIntent } from "./intents.js";
3
+ import type { RecordedProvisioning } from "./provisioning.js";
4
+ /** Start collecting declarations from the metadata bundle. */
5
+ export declare function startMetadataRecording(): RecordedProvisioning;
6
+ /** Finish the active metadata collection and return its declarations. */
7
+ export declare function finishMetadataRecording(recorder: RecordedProvisioning): RecordedProvisioning;
8
+ /** Record one declaration when metadata collection is active. */
9
+ export declare function recordIntent(intent: InfraAsCodeIntent): void;
10
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/notion-as-code/recorder.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAI9D,8DAA8D;AAC9D,wBAAgB,sBAAsB,IAAI,oBAAoB,CAI7D;AAED,yEAAyE;AACzE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,oBAAoB,CAM5F;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAE5D"}
@@ -0,0 +1,21 @@
1
+ let activeRecorder;
2
+ function startMetadataRecording() {
3
+ const recorder = { intents: [] };
4
+ activeRecorder = recorder;
5
+ return recorder;
6
+ }
7
+ function finishMetadataRecording(recorder) {
8
+ if (activeRecorder !== recorder) {
9
+ throw new Error("Notion-as-Code metadata recorder was replaced before build completed");
10
+ }
11
+ activeRecorder = void 0;
12
+ return recorder;
13
+ }
14
+ function recordIntent(intent) {
15
+ activeRecorder?.intents.push(intent);
16
+ }
17
+ export {
18
+ finishMetadataRecording,
19
+ recordIntent,
20
+ startMetadataRecording
21
+ };
@@ -0,0 +1,6 @@
1
+ import { type Parent } from "./intents.js";
2
+ /** Validate parent references accepted by Apps declarations. */
3
+ export declare function assertParent(parent: Parent): void;
4
+ /** Reject empty or runtime-reserved resource IDs in user declarations. */
5
+ export declare function assertUserResourceId(resourceId: string): void;
6
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/notion-as-code/resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE7E,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAKjD;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAO7D"}
@@ -0,0 +1,19 @@
1
+ import { APPS_RESERVED_RESOURCE_ID_PREFIX } from "./intents.js";
2
+ function assertParent(parent) {
3
+ if (parent.type !== "resourceId") {
4
+ throw new Error("Notion-as-Code parents must reference a resourceId");
5
+ }
6
+ assertUserResourceId(parent.resourceId);
7
+ }
8
+ function assertUserResourceId(resourceId) {
9
+ if (resourceId.length === 0) {
10
+ throw new Error("Notion-as-Code resourceId must be a non-empty string");
11
+ }
12
+ if (resourceId.startsWith(APPS_RESERVED_RESOURCE_ID_PREFIX)) {
13
+ throw new Error(`Resource ID "${resourceId}" uses the reserved Apps prefix`);
14
+ }
15
+ }
16
+ export {
17
+ assertParent,
18
+ assertUserResourceId
19
+ };
@@ -0,0 +1,63 @@
1
+ import { type Database } from "../database.js";
2
+ import type { PropertyConfiguration } from "../schema.js";
3
+ import type { SelectOption, StatusGroup } from "../types.js";
4
+ import type { DataSourceDefinition, NotionAsCodeProperty } from "./intents.js";
5
+ type AppsPropertyFor<Property extends NotionAsCodeProperty> = Property extends {
6
+ type: "title";
7
+ } ? {
8
+ type: "title";
9
+ } : Property extends {
10
+ type: "text";
11
+ } ? {
12
+ type: "text";
13
+ } : Property extends {
14
+ type: "number";
15
+ } ? {
16
+ type: "number";
17
+ } : Property extends {
18
+ type: "select";
19
+ } ? {
20
+ type: "select";
21
+ options: SelectOption[];
22
+ } : Property extends {
23
+ type: "multi_select";
24
+ } ? {
25
+ type: "multi_select";
26
+ options: SelectOption[];
27
+ } : Property extends {
28
+ type: "status";
29
+ } ? {
30
+ type: "status";
31
+ groups: StatusGroup[];
32
+ } : Property extends {
33
+ type: "date";
34
+ } ? {
35
+ type: "date";
36
+ } : Property extends {
37
+ type: "checkbox";
38
+ } ? {
39
+ type: "checkbox";
40
+ } : Property extends {
41
+ type: "url";
42
+ } ? {
43
+ type: "url";
44
+ } : Property extends {
45
+ type: "email";
46
+ } ? {
47
+ type: "email";
48
+ } : Property extends {
49
+ type: "phone_number";
50
+ } ? {
51
+ type: "phone_number";
52
+ } : Property extends {
53
+ type: "file";
54
+ } ? {
55
+ type: "file";
56
+ } : PropertyConfiguration;
57
+ export type AppsSchemaForProperties<Properties extends readonly NotionAsCodeProperty[]> = {
58
+ [Property in Properties[number] as Property["name"]]: AppsPropertyFor<Property>;
59
+ };
60
+ /** Convert a Notion-as-Code data source into the Apps database used by sync handlers. */
61
+ export declare function createAppsDatabase(databaseKey: string, dataSource: DataSourceDefinition): Database;
62
+ export {};
63
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/notion-as-code/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAkB,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EACX,oBAAoB,EACpB,oBAAoB,EAGpB,MAAM,cAAc,CAAC;AAEtB,KAAK,eAAe,CAAC,QAAQ,SAAS,oBAAoB,IAAI,QAAQ,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAC7F;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB,QAAQ,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB,QAAQ,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB,QAAQ,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,GAC3C,QAAQ,SAAS;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,GACjD,QAAQ,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,GACzC,QAAQ,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB,QAAQ,SAAS;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB,QAAQ,SAAS;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf,QAAQ,SAAS;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB,QAAQ,SAAS;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB,QAAQ,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB,qBAAqB,CAAC;AAEpC,MAAM,MAAM,uBAAuB,CAAC,UAAU,SAAS,SAAS,oBAAoB,EAAE,IAAI;KACxF,QAAQ,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC;CAC/E,CAAC;AAEF,yFAAyF;AACzF,wBAAgB,kBAAkB,CACjC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,oBAAoB,GAC9B,QAAQ,CAsCV"}
@@ -0,0 +1,94 @@
1
+ import { createDatabase } from "../database.js";
2
+ function createAppsDatabase(databaseKey, dataSource) {
3
+ const properties = {};
4
+ const propertyResourceIds = /* @__PURE__ */ new Set();
5
+ let titleCount = 0;
6
+ for (const property of dataSource.properties) {
7
+ if (property.resourceId.length === 0) {
8
+ throw new Error(
9
+ `Data source "${dataSource.resourceId}" has a property without a resourceId`
10
+ );
11
+ }
12
+ if (propertyResourceIds.has(property.resourceId)) {
13
+ throw new Error(
14
+ `Data source "${dataSource.resourceId}" has duplicate property resourceId "${property.resourceId}"`
15
+ );
16
+ }
17
+ if (properties[property.name] !== void 0) {
18
+ throw new Error(
19
+ `Data source "${dataSource.resourceId}" has duplicate property name "${property.name}"`
20
+ );
21
+ }
22
+ propertyResourceIds.add(property.resourceId);
23
+ if (property.type === "title") {
24
+ titleCount += 1;
25
+ }
26
+ properties[property.name] = toAppsProperty(dataSource.resourceId, property);
27
+ }
28
+ if (titleCount !== 1) {
29
+ throw new Error(
30
+ `Data source "${dataSource.resourceId}" must have exactly one title property to bind a sync`
31
+ );
32
+ }
33
+ return createDatabase(databaseKey, {
34
+ initialTitle: dataSource.name,
35
+ schema: properties
36
+ });
37
+ }
38
+ function toAppsProperty(dataSourceResourceId, property) {
39
+ switch (property.type) {
40
+ case "title":
41
+ return { type: "title" };
42
+ case "text":
43
+ return { type: "text" };
44
+ case "number":
45
+ return { type: "number" };
46
+ case "select":
47
+ return { type: "select", options: (property.options ?? []).map(toAppsSelectOption) };
48
+ case "multi_select":
49
+ return {
50
+ type: "multi_select",
51
+ options: (property.options ?? []).map(toAppsSelectOption)
52
+ };
53
+ case "status":
54
+ return {
55
+ type: "status",
56
+ groups: [
57
+ { name: "To-do", options: property.options.todo.map(toAppsStatusOption) },
58
+ {
59
+ name: "In progress",
60
+ options: property.options.inProgress.map(toAppsStatusOption)
61
+ },
62
+ {
63
+ name: "Complete",
64
+ options: property.options.complete.map(toAppsStatusOption)
65
+ }
66
+ ]
67
+ };
68
+ case "date":
69
+ return { type: "date" };
70
+ case "checkbox":
71
+ return { type: "checkbox" };
72
+ case "url":
73
+ return { type: "url" };
74
+ case "email":
75
+ return { type: "email" };
76
+ case "phone_number":
77
+ return { type: "phone_number" };
78
+ case "file":
79
+ return { type: "file" };
80
+ default:
81
+ throw new Error(
82
+ `Data source "${dataSourceResourceId}" property "${property.name}" uses unsupported sync type "${property.type}"`
83
+ );
84
+ }
85
+ }
86
+ function toAppsSelectOption(option) {
87
+ return option.color === void 0 ? { name: option.name } : { name: option.name, color: option.color };
88
+ }
89
+ function toAppsStatusOption(option) {
90
+ return option.color === void 0 ? { name: option.name } : { name: option.name, color: option.color };
91
+ }
92
+ export {
93
+ createAppsDatabase
94
+ };
@@ -0,0 +1,18 @@
1
+ import { type DataSourceDefinition, type NotionAsCodeIcon, type ResourceId } from "./intents.js";
2
+ import { type ChildDatabaseArgs, type DatabaseHandle } from "./database.js";
3
+ import { type ChildPageArgs, type PageHandle } from "./page.js";
4
+ export type TeamspaceArgs = {
5
+ resourceId: ResourceId;
6
+ name: string;
7
+ accessLevel: "default" | "open" | "closed" | "private";
8
+ icon?: NotionAsCodeIcon;
9
+ description?: string;
10
+ };
11
+ export type TeamspaceHandle = {
12
+ readonly resourceId: string;
13
+ addDatabase: <const DataSources extends readonly DataSourceDefinition[]>(args: ChildDatabaseArgs<DataSources>) => DatabaseHandle<DataSources>;
14
+ addPage: (args: ChildPageArgs) => PageHandle;
15
+ };
16
+ /** Declare a teamspace that Apps automatically creates in its workspace. */
17
+ export declare function teamspace(args: TeamspaceArgs): TeamspaceHandle;
18
+ //# sourceMappingURL=teamspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teamspace.d.ts","sourceRoot":"","sources":["../../src/notion-as-code/teamspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAEf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAY,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,EAAc,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAI5E,MAAM,MAAM,aAAa,GAAG;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvD,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,CAAC,KAAK,CAAC,WAAW,SAAS,SAAS,oBAAoB,EAAE,EACtE,IAAI,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAChC,cAAc,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,UAAU,CAAC;CAC7C,CAAC;AAEF,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,eAAe,CAoB9D"}
@@ -0,0 +1,30 @@
1
+ import {
2
+ APPS_WORKSPACE_RESOURCE_ID
3
+ } from "./intents.js";
4
+ import { database } from "./database.js";
5
+ import { createPage } from "./page.js";
6
+ import { recordIntent } from "./recorder.js";
7
+ import { assertUserResourceId } from "./resource.js";
8
+ function teamspace(args) {
9
+ assertUserResourceId(args.resourceId);
10
+ recordIntent({
11
+ type: "teamspace",
12
+ ...args,
13
+ parent: { type: "resourceId", resourceId: APPS_WORKSPACE_RESOURCE_ID }
14
+ });
15
+ return {
16
+ resourceId: args.resourceId,
17
+ addDatabase(databaseArgs) {
18
+ return database({
19
+ ...databaseArgs,
20
+ parent: { type: "resourceId", resourceId: args.resourceId }
21
+ });
22
+ },
23
+ addPage(pageArgs) {
24
+ return createPage(pageArgs, { type: "resourceId", resourceId: args.resourceId });
25
+ }
26
+ };
27
+ }
28
+ export {
29
+ teamspace
30
+ };
package/dist/sync.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import type { CapabilityContext } from "./context.js";
2
2
  import type { Database } from "./database.js";
3
+ import type { DataSourceHandle } from "./notion-as-code/database.js";
4
+ import type { NotionAsCodeProperty } from "./notion-as-code/intents.js";
5
+ import type { AppsSchemaForProperties } from "./notion-as-code/schema.js";
3
6
  import { type PacerEntry } from "./pacer.js";
4
7
  import type { DatabaseSchema, PropertyConfiguration, TextProperty, TitleProperty } from "./schema.js";
5
8
  import type { Cover, HandlerOptions, Icon, NormalizedSchedule, PeopleValue, PlaceValue, RelationValue, Schedule, TextValue } from "./types.js";
@@ -42,7 +45,15 @@ export type SyncConfiguration<S extends DatabaseSchema, PrimaryKey extends KeyPr
42
45
  primaryKey: PrimaryKey;
43
46
  mode?: SyncMode;
44
47
  schedule?: Schedule;
45
- handler: (state: State | undefined, context: CapabilityContext) => Promise<SyncHandlerResult<S, PrimaryKey, State>>;
48
+ handler: (state: State | undefined, context: CapabilityContext) => Promise<SyncHandlerResult<NoInfer<S>, NoInfer<PrimaryKey>, State>>;
49
+ };
50
+ /** Configuration for a sync backed by a Notion-as-Code data source. */
51
+ type DataSourceSyncConfiguration<Properties extends readonly NotionAsCodeProperty[], PrimaryKey extends KeyPropertyName<AppsSchemaForProperties<Properties>>, State> = {
52
+ dataSource: DataSourceHandle<Properties>;
53
+ primaryKey: PrimaryKey;
54
+ mode?: SyncMode;
55
+ schedule?: Schedule;
56
+ handler: (state: State | undefined, context: CapabilityContext) => Promise<SyncHandlerResult<NoInfer<AppsSchemaForProperties<Properties>>, NoInfer<PrimaryKey>, State>>;
46
57
  };
47
58
  export type SyncRuntimeContext = {
48
59
  state?: unknown;
@@ -66,7 +77,9 @@ export type Sync = {
66
77
  config: SyncDefinitionConfig;
67
78
  handler: (context?: SyncRuntimeContext, options?: HandlerOptions) => Promise<SyncRunResult>;
68
79
  };
69
- /** Create a database sync. Default-export it from a file in `src/syncs/`. */
80
+ /** Create a database sync. Default-export it from a sync file. */
70
81
  export declare function createSync<const S extends DatabaseSchema, const PrimaryKey extends KeyPropertyName<S>, State = unknown>(configuration: SyncConfiguration<S, PrimaryKey, State>): Sync;
82
+ /** Create a sync backed by a Notion-as-Code data source. */
83
+ export declare function createDataSourceSync<const Properties extends readonly NotionAsCodeProperty[], const PrimaryKey extends KeyPropertyName<AppsSchemaForProperties<Properties>>, State = unknown>(configuration: DataSourceSyncConfiguration<Properties, PrimaryKey, State>): Sync;
71
84
  export {};
72
85
  //# sourceMappingURL=sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
package/dist/sync.js CHANGED
@@ -4,10 +4,20 @@ import { writeOutput } from "./output.js";
4
4
  import { initPacerState, pacerStates } from "./pacer.js";
5
5
  import { resolveRuntimeInput } from "./runtime-input.js";
6
6
  import { parseSchedule } from "./schedule.js";
7
+ function resolveSyncDatabase(configuration) {
8
+ return "dataSource" in configuration ? configuration.dataSource.database : configuration.database;
9
+ }
7
10
  function createSync(configuration) {
11
+ return createSyncDefinition(configuration);
12
+ }
13
+ function createDataSourceSync(configuration) {
14
+ return createSyncDefinition(configuration);
15
+ }
16
+ function createSyncDefinition(configuration) {
8
17
  const schedule = configuration.schedule === void 0 ? void 0 : parseSchedule(configuration.schedule);
18
+ const database = resolveSyncDatabase(configuration);
9
19
  const config = {
10
- database: configuration.database,
20
+ database,
11
21
  primaryKeyProperty: configuration.primaryKey,
12
22
  ...configuration.mode === void 0 ? {} : { mode: configuration.mode },
13
23
  ...schedule === void 0 ? {} : { schedule }
@@ -23,7 +33,7 @@ function createSync(configuration) {
23
33
  const handlerResult = await configuration.handler(state, createCapabilityContext());
24
34
  const changes = handlerResult.changes.map((change) => {
25
35
  if (change.type === "delete") {
26
- return { ...change, targetDatabaseKey: configuration.database.key };
36
+ return { ...change, targetDatabaseKey: database.key };
27
37
  }
28
38
  return {
29
39
  ...change,
@@ -31,7 +41,7 @@ function createSync(configuration) {
31
41
  ...change.properties,
32
42
  [configuration.primaryKey]: [[change.key]]
33
43
  },
34
- targetDatabaseKey: configuration.database.key
44
+ targetDatabaseKey: database.key
35
45
  };
36
46
  });
37
47
  const result = {
@@ -71,5 +81,6 @@ function createSync(configuration) {
71
81
  };
72
82
  }
73
83
  export {
84
+ createDataSourceSync,
74
85
  createSync
75
86
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/apps",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "An SDK for building workflow apps for Notion",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -58,6 +58,14 @@
58
58
  "./workflow": {
59
59
  "types": "./dist/workflow.d.ts",
60
60
  "default": "./dist/workflow.js"
61
+ },
62
+ "./notion-as-code": {
63
+ "types": "./dist/notion-as-code/index.d.ts",
64
+ "default": "./dist/notion-as-code/index.js"
65
+ },
66
+ "./notion-as-code/recorder": {
67
+ "types": "./dist/notion-as-code/recorder.d.ts",
68
+ "default": "./dist/notion-as-code/recorder.js"
61
69
  }
62
70
  },
63
71
  "publishConfig": {
@@ -34,7 +34,7 @@ afterEach(async () => {
34
34
  });
35
35
 
36
36
  describe("buildApp", () => {
37
- it("builds a sync manifest with an attached database contract", async () => {
37
+ it("builds a sync manifest with a Notion-as-Code meetings database", async () => {
38
38
  const { manifest } = await buildApp(example("sync"));
39
39
 
40
40
  expect(manifest).toEqual({
@@ -54,6 +54,20 @@ describe("buildApp", () => {
54
54
  },
55
55
  },
56
56
  },
57
+ {
58
+ key: "homebase-meetings-source",
59
+ config: {
60
+ initialTitle: "Meetings",
61
+ schema: {
62
+ properties: {
63
+ Name: { type: "title" },
64
+ "Meeting ID": { type: "text" },
65
+ "Meeting date": { type: "date" },
66
+ "Prep complete": { type: "checkbox" },
67
+ },
68
+ },
69
+ },
70
+ },
57
71
  ],
58
72
  xldbs: [],
59
73
  pacers: [],
@@ -68,6 +82,82 @@ describe("buildApp", () => {
68
82
  schedule: { type: "interval", intervalMs: 3_600_000 },
69
83
  },
70
84
  },
85
+ {
86
+ type: "sync",
87
+ key: "notionAsCodeIssues",
88
+ config: {
89
+ databaseKey: "homebase-meetings-source",
90
+ primaryKeyProperty: "Meeting ID",
91
+ mode: "incremental",
92
+ schedule: { type: "interval", intervalMs: 3_600_000 },
93
+ },
94
+ },
95
+ ],
96
+ });
97
+ });
98
+
99
+ it("emits a separate Notion-as-Code provisioning artifact", async () => {
100
+ const projectRoot = fixture("notion-as-code");
101
+ const { manifest } = await buildApp(projectRoot);
102
+
103
+ expect(manifest.databases).toEqual([
104
+ {
105
+ key: "issues-source",
106
+ config: {
107
+ initialTitle: "GitHub Issues",
108
+ schema: {
109
+ properties: {
110
+ Name: { type: "title" },
111
+ "GitHub ID": { type: "text" },
112
+ Closed: { type: "checkbox" },
113
+ },
114
+ },
115
+ },
116
+ },
117
+ ]);
118
+ expect(manifest.capabilities).toEqual([
119
+ {
120
+ type: "sync",
121
+ key: "issues",
122
+ config: {
123
+ databaseKey: "issues-source",
124
+ primaryKeyProperty: "GitHub ID",
125
+ },
126
+ },
127
+ ]);
128
+ expect(
129
+ JSON.parse(
130
+ await fs.promises.readFile(
131
+ path.join(projectRoot, "dist", "provisioning.json"),
132
+ "utf8",
133
+ ),
134
+ ),
135
+ ).toEqual({
136
+ $schema: "notion:apps-provisioning:v1",
137
+ version: 1,
138
+ intents: [
139
+ {
140
+ type: "teamspace",
141
+ resourceId: "github-app-teamspace",
142
+ name: "GitHub app data",
143
+ accessLevel: "open",
144
+ },
145
+ {
146
+ type: "database",
147
+ resourceId: "issues-db",
148
+ parent: { type: "resourceId", resourceId: "github-app-teamspace" },
149
+ dataSources: [
150
+ {
151
+ resourceId: "issues-source",
152
+ name: "GitHub Issues",
153
+ properties: [
154
+ { resourceId: "issues-name", name: "Name", type: "title" },
155
+ { resourceId: "issues-github-id", name: "GitHub ID", type: "text" },
156
+ { resourceId: "issues-closed", name: "Closed", type: "checkbox" },
157
+ ],
158
+ },
159
+ ],
160
+ },
71
161
  ],
72
162
  });
73
163
  });