@notionhq/apps 0.0.47 → 0.0.49

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.
@@ -1,6 +1,6 @@
1
1
  import { type Parent } from "./intents.js";
2
- /** Validate parent references accepted by Apps declarations. */
2
+ /** Validate parent references. Reserved Apps IDs are allowed as parents. */
3
3
  export declare function assertParent(parent: Parent): void;
4
- /** Reject empty or runtime-reserved resource IDs in user declarations. */
4
+ /** Reject empty or runtime-reserved IDs for created resources. */
5
5
  export declare function assertUserResourceId(resourceId: string): void;
6
6
  //# sourceMappingURL=resource.d.ts.map
@@ -1 +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"}
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,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAOjD;AAED,kEAAkE;AAClE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAO7D"}
@@ -3,7 +3,9 @@ function assertParent(parent) {
3
3
  if (parent.type !== "resourceId") {
4
4
  throw new Error("Notion-as-Code parents must reference a resourceId");
5
5
  }
6
- assertUserResourceId(parent.resourceId);
6
+ if (parent.resourceId.length === 0) {
7
+ throw new Error("Notion-as-Code resourceId must be a non-empty string");
8
+ }
7
9
  }
8
10
  function assertUserResourceId(resourceId) {
9
11
  if (resourceId.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/apps",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
4
4
  "description": "An SDK for building workflow apps for Notion",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -155,8 +155,10 @@ Custom views do not accept standard view properties, sorts, or filters. Keep
155
155
  the view resource ID and the custom-block filename stable across builds.
156
156
 
157
157
  Keep resource IDs stable across builds. They identify declarations, not live
158
- Notion UUIDs. Avoid the reserved `__notion_apps_` prefix. Explicit parents
159
- use `{ type: "resourceId", resourceId: parent.resourceId }`; child helpers set
158
+ Notion UUIDs. Do not create resources whose IDs use the reserved
159
+ `__notion_apps_` prefix. Parenting to reserved IDs such as
160
+ `__notion_apps_app_md__` is allowed. Explicit parents use
161
+ `{ type: "resourceId", resourceId: parent.resourceId }`; child helpers set
160
162
  this reference for you. Pages and databases without a parent default to private
161
163
  top-level resources in the Apps workspace.
162
164
 
@@ -156,7 +156,10 @@ configuration, and do not log secrets or private payloads.
156
156
 
157
157
  ## Manual workflow inputs
158
158
 
159
- Provide up to one `events.manual` to allow triggering the workflow manually from the UI or CLI for testing purposes.
159
+ Provide up to one `events.manual()` to allow triggering the workflow from the UI
160
+ or CLI on demand. For scheduled workflows, include it alongside
161
+ `events.scheduled()` so users can run the workflow without waiting for the next
162
+ scheduled time.
160
163
 
161
164
  Specify the inputs accepted using `@notionhq/apps/schema-builder`.
162
165
 
@@ -247,7 +250,7 @@ import { guide } from "./sayHello/lib/notion.js";
247
250
  export default workflow({
248
251
  name: "Read guide",
249
252
  description: "Reads the App's guide on a recurring schedule.",
250
- triggers: [events.scheduled()],
253
+ triggers: [events.scheduled(), events.manual()],
251
254
  access: { guide: access.view(guide) },
252
255
  handler: async (_event, context) => {
253
256
  await context.step("Read guide", () =>
@@ -262,11 +265,6 @@ declarations in `access` work too. Importing a declaration alone provisions the
262
265
  resource but does not create a `context.access` alias. An `access` entry declares
263
266
  the needed permission level and a named binding for that NaC resource.
264
267
 
265
- For a workflow that uses `events.scheduled()`, also declare a "triggers"
266
- database with a page-added trigger bound to it. This lets the user manually
267
- trigger a run at any time by adding a page to that database, without waiting
268
- for the schedule.
269
-
270
268
  `access.view()`, `access.comment()`, `access.edit()`, and `access.fullAccess()`
271
269
  accept page, database, and data-source handles. `access.call()` accepts custom-agent
272
270
  handles. Keys are workflow-local aliases. The handler's
@@ -791,6 +791,32 @@ describe("Notion-as-Code database declarations", () => {
791
791
  expect(serialized.description).toBe("Metadata source");
792
792
  });
793
793
 
794
+ it("allows parenting a database to a reserved Apps resource ID", () => {
795
+ const recorder = startMetadataRecording();
796
+ notion.database("meetings-db", {
797
+ parent: { type: "resourceId", resourceId: "__notion_apps_app_md__" },
798
+ dataSourceResourceId: "meetings-source",
799
+ name: "Meetings",
800
+ schema: { Name: { resourceId: "meeting-name", type: "title" } },
801
+ });
802
+ expect(finishMetadataRecording(recorder).intents[0]).toEqual(
803
+ expect.objectContaining({
804
+ resourceId: "meetings-db",
805
+ parent: { type: "resourceId", resourceId: "__notion_apps_app_md__" },
806
+ }),
807
+ );
808
+ });
809
+
810
+ it("rejects creating a database whose resource ID uses the reserved Apps prefix", () => {
811
+ expect(() =>
812
+ notion.database("__notion_apps_meetings__", {
813
+ dataSourceResourceId: "meetings-source",
814
+ name: "Meetings",
815
+ schema: { Name: { resourceId: "meeting-name", type: "title" } },
816
+ }),
817
+ ).toThrow('Resource ID "__notion_apps_meetings__" uses the reserved Apps prefix');
818
+ });
819
+
794
820
  it("requires the status property configuration in authoring types", () => {
795
821
  const invalidStatusDeclaration = () =>
796
822
  notion.database("missing-status-options-database", {
@@ -28,6 +28,30 @@ describe("Notion-as-Code page declarations", () => {
28
28
  ]);
29
29
  });
30
30
 
31
+ it("allows parenting a page to a reserved Apps resource ID", () => {
32
+ const recorder = startMetadataRecording();
33
+ notion.page({
34
+ resourceId: "guide",
35
+ parent: { type: "resourceId", resourceId: "__notion_apps_app_md__" },
36
+ properties: { title: notion.text("Guide") },
37
+ });
38
+ expect(finishMetadataRecording(recorder).intents[0]).toEqual(
39
+ expect.objectContaining({
40
+ resourceId: "guide",
41
+ parent: { type: "resourceId", resourceId: "__notion_apps_app_md__" },
42
+ }),
43
+ );
44
+ });
45
+
46
+ it("rejects creating a page whose resource ID uses the reserved Apps prefix", () => {
47
+ expect(() =>
48
+ notion.page({
49
+ resourceId: "__notion_apps_guide__",
50
+ properties: { title: notion.text("Guide") },
51
+ }),
52
+ ).toThrow('Resource ID "__notion_apps_guide__" uses the reserved Apps prefix');
53
+ });
54
+
31
55
  it("records a regular page title separately from Markdown content", () => {
32
56
  const properties = {
33
57
  title: notion.text("Workflow guide"),
@@ -1,14 +1,16 @@
1
1
  import { APPS_RESERVED_RESOURCE_ID_PREFIX, type Parent } from "./intents.js";
2
2
 
3
- /** Validate parent references accepted by Apps declarations. */
3
+ /** Validate parent references. Reserved Apps IDs are allowed as parents. */
4
4
  export function assertParent(parent: Parent): void {
5
5
  if (parent.type !== "resourceId") {
6
6
  throw new Error("Notion-as-Code parents must reference a resourceId");
7
7
  }
8
- assertUserResourceId(parent.resourceId);
8
+ if (parent.resourceId.length === 0) {
9
+ throw new Error("Notion-as-Code resourceId must be a non-empty string");
10
+ }
9
11
  }
10
12
 
11
- /** Reject empty or runtime-reserved resource IDs in user declarations. */
13
+ /** Reject empty or runtime-reserved IDs for created resources. */
12
14
  export function assertUserResourceId(resourceId: string): void {
13
15
  if (resourceId.length === 0) {
14
16
  throw new Error("Notion-as-Code resourceId must be a non-empty string");