@notionhq/apps 0.0.14 → 0.0.15
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/README.md +84 -27
- package/dist/cli/emit-manifest.d.ts.map +1 -1
- package/dist/cli/emit-manifest.js +1 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +3 -0
- package/dist/context.test.d.ts +2 -0
- package/dist/context.test.d.ts.map +1 -0
- package/dist/custom-block.d.ts +1 -1
- package/dist/custom-block.d.ts.map +1 -1
- package/dist/custom-block.js +3 -3
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/sync.d.ts +2 -2
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +3 -3
- package/dist/workflow.d.ts +6 -6
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +2 -2
- package/docs/BUILD.md +5 -5
- package/docs/CONNECTIONS.md +5 -4
- package/package.json +5 -1
- package/src/cli/build.test.ts +2 -4
- package/src/cli/emit-manifest.ts +1 -5
- package/src/context.test.ts +26 -0
- package/src/context.ts +8 -0
- package/src/custom-block.test.ts +4 -4
- package/src/custom-block.ts +2 -2
- package/src/index.ts +7 -0
- package/src/sync.ts +2 -2
- package/src/workflow-connections-types.test.ts +6 -6
- package/src/workflow-types.test.ts +2 -2
- package/src/workflow.test.ts +31 -31
- package/src/workflow.ts +7 -7
package/README.md
CHANGED
|
@@ -3,6 +3,66 @@
|
|
|
3
3
|
[](https://github.com/makenotion/apps-sdk/actions/workflows/ci.yml?query=branch%3Amain)
|
|
4
4
|
[](https://github.com/makenotion/apps-sdk/actions/workflows/publish.yml?query=branch%3Amain)
|
|
5
5
|
|
|
6
|
+
## Imports
|
|
7
|
+
|
|
8
|
+
The package root exports only resource and capability creation helpers:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import {
|
|
12
|
+
page,
|
|
13
|
+
database,
|
|
14
|
+
teamspace,
|
|
15
|
+
customAgent,
|
|
16
|
+
sync,
|
|
17
|
+
workflow,
|
|
18
|
+
customBlock,
|
|
19
|
+
} from "@notionhq/apps";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Import the helpers your app uses:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { page, workflow } from "@notionhq/apps";
|
|
26
|
+
|
|
27
|
+
const home = page({ resourceId: "home" });
|
|
28
|
+
|
|
29
|
+
export default workflow({
|
|
30
|
+
name: "Follow up",
|
|
31
|
+
description: "Runs when a page is created",
|
|
32
|
+
triggers: ({ triggers }) => [triggers.notionPageCreated()],
|
|
33
|
+
handler: async () => {},
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Namespace imports (`import * as Notion from "@notionhq/apps"`) are also supported
|
|
38
|
+
for autocomplete and API exploration.
|
|
39
|
+
|
|
40
|
+
`sync` accepts a Notion-as-Code data-source handle. `customBlock` creates a custom-block
|
|
41
|
+
capability; it is not the browser runtime object. The capability factories use these
|
|
42
|
+
short names on both the root and their subpaths. Their behavior is unchanged.
|
|
43
|
+
|
|
44
|
+
The old capability factory names are no longer exported. Update existing imports and calls:
|
|
45
|
+
|
|
46
|
+
| Removed name | Use instead | Subpath |
|
|
47
|
+
| ---------------------- | ------------- | ----------------------------- |
|
|
48
|
+
| `createWorkflow` | `workflow` | `@notionhq/apps/workflow` |
|
|
49
|
+
| `createDataSourceSync` | `sync` | `@notionhq/apps/sync` |
|
|
50
|
+
| `createCustomBlock` | `customBlock` | `@notionhq/apps/custom-block` |
|
|
51
|
+
|
|
52
|
+
Everything else keeps its subpath import, including builders, value helpers, types,
|
|
53
|
+
connections, triggers, pacers, and the custom-block browser runtime:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { Builder } from "@notionhq/apps/builder";
|
|
57
|
+
import { notion } from "@notionhq/apps/notion-as-code";
|
|
58
|
+
import type { DataSourceSyncConfiguration } from "@notionhq/apps/sync";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Existing subpaths remain available, with the capability factory renames above. The root
|
|
62
|
+
uses explicit exports and does not re-export utility types or the custom-block browser runtime. Browser code should
|
|
63
|
+
keep using `@notionhq/apps/custom-blocks` and `@notionhq/apps/react`; the root includes
|
|
64
|
+
Node-only workflow code. Styles stay in `@notionhq/apps/nds.css`.
|
|
65
|
+
|
|
6
66
|
## Development
|
|
7
67
|
|
|
8
68
|
1. Install [mise](https://mise.jdx.dev/getting-started.html)
|
|
@@ -14,13 +74,14 @@ The SDK requires Node 26 or newer. It supports workflows and database syncs.
|
|
|
14
74
|
|
|
15
75
|
```ts
|
|
16
76
|
import { triggers } from "@notionhq/apps/triggers";
|
|
17
|
-
import {
|
|
77
|
+
import { workflow } from "@notionhq/apps";
|
|
78
|
+
import { connections } from "@notionhq/apps/workflow";
|
|
18
79
|
```
|
|
19
80
|
|
|
20
81
|
Add a connection requirement to a workflow when it needs Calendar:
|
|
21
82
|
|
|
22
83
|
```ts
|
|
23
|
-
export default
|
|
84
|
+
export default workflow({
|
|
24
85
|
name: "Schedule follow-up",
|
|
25
86
|
description: "Schedules a follow-up after a page is created",
|
|
26
87
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -37,26 +98,30 @@ Use `context.notion` for Notion API calls. Deployed apps receive Notion API
|
|
|
37
98
|
credentials automatically, so do not configure or push `NOTION_API_TOKEN`.
|
|
38
99
|
Local execution needs the token in `.env` before making a Notion API request.
|
|
39
100
|
|
|
40
|
-
##
|
|
101
|
+
## Data-source syncs
|
|
41
102
|
|
|
42
|
-
|
|
43
|
-
databases are always attached; there is no managed-database option.
|
|
103
|
+
Declare a database with Notion as Code, then pass one of its data-source handles to `sync`:
|
|
44
104
|
|
|
45
105
|
```ts
|
|
106
|
+
import { database, sync } from "@notionhq/apps";
|
|
46
107
|
import { Builder } from "@notionhq/apps/builder";
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
108
|
+
|
|
109
|
+
const issues = database({
|
|
110
|
+
resourceId: "issues-db",
|
|
111
|
+
dataSources: [
|
|
112
|
+
{
|
|
113
|
+
resourceId: "issues-source",
|
|
114
|
+
name: "GitHub Issues",
|
|
115
|
+
properties: [
|
|
116
|
+
{ resourceId: "name", name: "Name", type: "title" },
|
|
117
|
+
{ resourceId: "github-id", name: "GitHub ID", type: "text" },
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
],
|
|
56
121
|
});
|
|
57
122
|
|
|
58
|
-
export default
|
|
59
|
-
|
|
123
|
+
export default sync({
|
|
124
|
+
dataSource: issues.dataSources["issues-source"],
|
|
60
125
|
primaryKey: "GitHub ID",
|
|
61
126
|
handler: async () => ({
|
|
62
127
|
changes: [
|
|
@@ -71,7 +136,7 @@ export default createSync({
|
|
|
71
136
|
```
|
|
72
137
|
|
|
73
138
|
Put each default-exported sync directly in `src/syncs/`. A primary key must be a title
|
|
74
|
-
or
|
|
139
|
+
or text property. Do not include that property in an upsert: the SDK fills it from
|
|
75
140
|
the change's `key`.
|
|
76
141
|
|
|
77
142
|
## Custom blocks
|
|
@@ -79,9 +144,9 @@ the change's `key`.
|
|
|
79
144
|
Declare browser blocks in `src/customBlocks/<key>.ts`:
|
|
80
145
|
|
|
81
146
|
```ts
|
|
82
|
-
import {
|
|
147
|
+
import { customBlock } from "@notionhq/apps";
|
|
83
148
|
|
|
84
|
-
export default
|
|
149
|
+
export default customBlock({
|
|
85
150
|
path: "./blocks/hello",
|
|
86
151
|
slashCommand: "hello",
|
|
87
152
|
dataSources: {},
|
|
@@ -94,14 +159,6 @@ export default createCustomBlock({
|
|
|
94
159
|
See [the build and deployment guide](docs/BUILD.md) for provisioning artifacts,
|
|
95
160
|
cloud builds with server coordination, and local builds with CLI coordination.
|
|
96
161
|
|
|
97
|
-
### Moving from the Workers alpha SDK
|
|
98
|
-
|
|
99
|
-
- Remove `type` and `primaryKey` from `createDatabase`.
|
|
100
|
-
- Move the property map from `schema.properties` directly into `schema`.
|
|
101
|
-
- Add `primaryKey` to each `createSync`.
|
|
102
|
-
- Remove the primary-key property from each upsert's `properties` object.
|
|
103
|
-
- Change imports from `@notionhq/workers/alpha/*` to `@notionhq/apps/*`.
|
|
104
|
-
|
|
105
162
|
## Local / Boxy end to end testing
|
|
106
163
|
|
|
107
164
|
To build and deploy the app template against a running local Notion server:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit-manifest.d.ts","sourceRoot":"","sources":["../../src/cli/emit-manifest.ts"],"names":[],"mappings":"AAMA,OAAO,EAEN,KAAK,oBAAoB,EACzB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAA6C,MAAM,gBAAgB,CAAC;AAE7F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AA0M1D,oDAAoD;AACpD,wBAAsB,eAAe,CACpC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,SAAS,oBAAoB,EAAE,EAC7C,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACxC,OAAO,CAAC,WAAW,CAAC,CAiFtB;AAED,uFAAuF;AACvF,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAW3F;
|
|
1
|
+
{"version":3,"file":"emit-manifest.d.ts","sourceRoot":"","sources":["../../src/cli/emit-manifest.ts"],"names":[],"mappings":"AAMA,OAAO,EAEN,KAAK,oBAAoB,EACzB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAA6C,MAAM,gBAAgB,CAAC;AAE7F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AA0M1D,oDAAoD;AACpD,wBAAsB,eAAe,CACpC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,SAAS,oBAAoB,EAAE,EAC7C,YAAY,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACxC,OAAO,CAAC,WAAW,CAAC,CAiFtB;AAED,uFAAuF;AACvF,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAW3F;AA8BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAoCjE;AAED,yFAAyF;AACzF,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAE9F"}
|
|
@@ -174,7 +174,7 @@ async function extractManifest(bundlePath, capabilities, blockConfigs = {}) {
|
|
|
174
174
|
);
|
|
175
175
|
if (!tagged || tagged._tag !== capability.tag) {
|
|
176
176
|
throw new Error(
|
|
177
|
-
`${capability.sourcePath}: default export is not a ${capability.type} \u2014 files under this directory must default-export
|
|
177
|
+
`${capability.sourcePath}: default export is not a ${capability.type} \u2014 files under this directory must default-export ${capability.type === "custom_block" ? "customBlock" : capability.type}(...)`
|
|
178
178
|
);
|
|
179
179
|
}
|
|
180
180
|
let config = { ...tagged.config };
|
|
@@ -249,9 +249,6 @@ function getCapabilityRegistry(bundle) {
|
|
|
249
249
|
}
|
|
250
250
|
return bundle.capabilities;
|
|
251
251
|
}
|
|
252
|
-
function capitalize(value) {
|
|
253
|
-
return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
|
|
254
|
-
}
|
|
255
252
|
function assertJsonSafe(value, path) {
|
|
256
253
|
const reject = (reason) => {
|
|
257
254
|
throw new Error(`${path}: not JSON-serializable (${reason})`);
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,MAAM,MAAM,iBAAiB,GAAG;IAC/B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,MAAM,MAAM,iBAAiB,GAAG;IAC/B,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAmCF,wBAAgB,uBAAuB,IAAI,iBAAiB,CAe3D"}
|
package/dist/context.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Client } from "@notionhq/client";
|
|
2
2
|
const LOCAL_FIX_STEPS = "\n\nFor local execution:\n1. Create a personal access token at https://app.notion.com/developers/tokens\n2. Add NOTION_API_TOKEN=<your-token> to your .env file\n\nDeployed apps receive Notion API credentials automatically. Do not push NOTION_API_TOKEN.";
|
|
3
3
|
function missingTokenMessage() {
|
|
4
|
+
if (process.env.NOTION_WORKFLOW_STEP_DIRECTORY) {
|
|
5
|
+
return "Notion API access is not configured for this deployed workflow. In Notion, open Developer Tools \u2192 Workers, select this workflow, and grant access to the pages or databases it uses. The runtime provides NOTION_API_TOKEN automatically after access is configured; do not set or push it yourself.";
|
|
6
|
+
}
|
|
4
7
|
return "NOTION_API_TOKEN is not set. context.notion requires an API token when an app capability runs locally." + LOCAL_FIX_STEPS;
|
|
5
8
|
}
|
|
6
9
|
function createUnauthenticatedNotionProxy() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.test.d.ts","sourceRoot":"","sources":["../src/context.test.ts"],"names":[],"mappings":""}
|
package/dist/custom-block.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type CustomBlockOptions = {
|
|
|
13
13
|
output?: string;
|
|
14
14
|
});
|
|
15
15
|
/** Declare a browser project. Its filename under src/customBlocks supplies its key. */
|
|
16
|
-
export declare function
|
|
16
|
+
export declare function customBlock(options: CustomBlockOptions): {
|
|
17
17
|
_tag: "custom_block";
|
|
18
18
|
config: {
|
|
19
19
|
source: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-block.d.ts","sourceRoot":"","sources":["../src/custom-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CACjD,GAAG,CACD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,GACjD;IAAE,MAAM,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CACvD,CAAC;AAEF,uFAAuF;AACvF,wBAAgB,
|
|
1
|
+
{"version":3,"file":"custom-block.d.ts","sourceRoot":"","sources":["../src/custom-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CACjD,GAAG,CACD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,GACjD;IAAE,MAAM,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CACvD,CAAC;AAEF,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4BtD"}
|
package/dist/custom-block.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
function
|
|
1
|
+
function customBlock(options) {
|
|
2
2
|
if (typeof options.path !== "string" || options.path.trim() === "") {
|
|
3
|
-
throw new Error("
|
|
3
|
+
throw new Error("customBlock requires a non-empty path relative to the app root");
|
|
4
4
|
}
|
|
5
5
|
const slashCommand = options.slashCommand?.replace(/^\//, "");
|
|
6
6
|
if (slashCommand !== void 0 && !/^[a-z0-9][a-z0-9_-]{0,63}$/.test(slashCommand)) {
|
|
@@ -26,5 +26,5 @@ function createCustomBlock(options) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
export {
|
|
29
|
-
|
|
29
|
+
customBlock
|
|
30
30
|
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { customBlock } from "./custom-block.js";
|
|
2
|
+
export { customAgent } from "./notion-as-code/custom-agent.js";
|
|
3
|
+
export { database } from "./notion-as-code/database.js";
|
|
4
|
+
export { page } from "./notion-as-code/page.js";
|
|
5
|
+
export { teamspace } from "./notion-as-code/teamspace.js";
|
|
6
|
+
export { sync } from "./sync.js";
|
|
7
|
+
export { workflow } from "./workflow.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { customBlock } from "./custom-block.js";
|
|
2
|
+
import { customAgent } from "./notion-as-code/custom-agent.js";
|
|
3
|
+
import { database } from "./notion-as-code/database.js";
|
|
4
|
+
import { page } from "./notion-as-code/page.js";
|
|
5
|
+
import { teamspace } from "./notion-as-code/teamspace.js";
|
|
6
|
+
import { sync } from "./sync.js";
|
|
7
|
+
import { workflow } from "./workflow.js";
|
|
8
|
+
export {
|
|
9
|
+
customAgent,
|
|
10
|
+
customBlock,
|
|
11
|
+
database,
|
|
12
|
+
page,
|
|
13
|
+
sync,
|
|
14
|
+
teamspace,
|
|
15
|
+
workflow
|
|
16
|
+
};
|
package/dist/sync.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ export type SyncConfiguration<S extends DatabaseSchema, PrimaryKey extends KeyPr
|
|
|
48
48
|
handler: (state: State | undefined, context: CapabilityContext) => Promise<SyncHandlerResult<NoInfer<S>, NoInfer<PrimaryKey>, State>>;
|
|
49
49
|
};
|
|
50
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> = {
|
|
51
|
+
export type DataSourceSyncConfiguration<Properties extends readonly NotionAsCodeProperty[], PrimaryKey extends KeyPropertyName<AppsSchemaForProperties<Properties>>, State> = {
|
|
52
52
|
dataSource: DataSourceHandle<Properties>;
|
|
53
53
|
primaryKey: PrimaryKey;
|
|
54
54
|
mode?: SyncMode;
|
|
@@ -80,6 +80,6 @@ export type Sync = {
|
|
|
80
80
|
/** Create a database sync. Default-export it from a sync file. */
|
|
81
81
|
export declare function createSync<const S extends DatabaseSchema, const PrimaryKey extends KeyPropertyName<S>, State = unknown>(configuration: SyncConfiguration<S, PrimaryKey, State>): Sync;
|
|
82
82
|
/** Create a sync backed by a Notion-as-Code data source. */
|
|
83
|
-
export declare function
|
|
83
|
+
export declare function sync<const Properties extends readonly NotionAsCodeProperty[], const PrimaryKey extends KeyPropertyName<AppsSchemaForProperties<Properties>>, State = unknown>(configuration: DataSourceSyncConfiguration<Properties, PrimaryKey, State>): Sync;
|
|
84
84
|
export {};
|
|
85
85
|
//# sourceMappingURL=sync.d.ts.map
|
package/dist/sync.d.ts.map
CHANGED
|
@@ -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
|
@@ -10,7 +10,7 @@ function resolveSyncDatabase(configuration) {
|
|
|
10
10
|
function createSync(configuration) {
|
|
11
11
|
return createSyncDefinition(configuration);
|
|
12
12
|
}
|
|
13
|
-
function
|
|
13
|
+
function sync(configuration) {
|
|
14
14
|
return createSyncDefinition(configuration);
|
|
15
15
|
}
|
|
16
16
|
function createSyncDefinition(configuration) {
|
|
@@ -81,6 +81,6 @@ function createSyncDefinition(configuration) {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
export {
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
createSync,
|
|
85
|
+
sync
|
|
86
86
|
};
|
package/dist/workflow.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type WorkflowEventForTrigger<T extends WorkflowTrigger> = WorkflowEventMa
|
|
|
11
11
|
export type WorkflowEventForTriggers<T extends readonly WorkflowTrigger[]> = WorkflowEventForTrigger<T[number]>;
|
|
12
12
|
export { connections, type WorkflowConnection, type WorkflowConnections } from "./connections.js";
|
|
13
13
|
/**
|
|
14
|
-
* Configuration passed to {@link
|
|
14
|
+
* Configuration passed to {@link workflow}.
|
|
15
15
|
*/
|
|
16
16
|
export type WorkflowConfiguration<TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]], TConnections extends readonly WorkflowConnection[] = readonly WorkflowConnection[]> = {
|
|
17
17
|
/**
|
|
@@ -41,7 +41,7 @@ export type WorkflowTriggerConfiguration<TTriggers extends readonly [WorkflowTri
|
|
|
41
41
|
}) => TTriggers;
|
|
42
42
|
};
|
|
43
43
|
/**
|
|
44
|
-
* A workflow capability as returned by {@link
|
|
44
|
+
* A workflow capability as returned by {@link workflow}.
|
|
45
45
|
*
|
|
46
46
|
* Note that a workflow carries no key of its own — the build tool derives
|
|
47
47
|
* the capability key from the file the workflow is default-exported from.
|
|
@@ -71,9 +71,9 @@ export type Workflow<TTriggers extends readonly [WorkflowTrigger, ...WorkflowTri
|
|
|
71
71
|
* ```ts
|
|
72
72
|
* // src/workflows/onPageCreated.ts
|
|
73
73
|
* import { triggers } from "@notionhq/apps/triggers";
|
|
74
|
-
* import {
|
|
74
|
+
* import { workflow } from "@notionhq/apps/workflow";
|
|
75
75
|
*
|
|
76
|
-
* export default
|
|
76
|
+
* export default workflow({
|
|
77
77
|
* name: "Send Welcome Email",
|
|
78
78
|
* description: "Sends a welcome email when a new page is added",
|
|
79
79
|
* triggers: [triggers.notionPageCreated()],
|
|
@@ -87,11 +87,11 @@ export type Workflow<TTriggers extends readonly [WorkflowTrigger, ...WorkflowTri
|
|
|
87
87
|
* });
|
|
88
88
|
* ```
|
|
89
89
|
*/
|
|
90
|
-
export declare function
|
|
90
|
+
export declare function workflow<const TTriggers extends readonly [
|
|
91
91
|
WorkflowTriggerForConnections<NoInfer<TConnections>>,
|
|
92
92
|
...WorkflowTriggerForConnections<NoInfer<TConnections>>[]
|
|
93
93
|
], const TConnections extends readonly WorkflowConnection[] = readonly []>(configuration: WorkflowTriggerConfiguration<TTriggers, TConnections>): Workflow<TTriggers>;
|
|
94
|
-
export declare function
|
|
94
|
+
export declare function workflow<const TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]], const TConnections extends readonly WorkflowConnection[] = readonly []>(configuration: WorkflowConfiguration<TTriggers, TConnections>): Workflow<TTriggers>;
|
|
95
95
|
/** Context passed to a workflow step. */
|
|
96
96
|
export type StepContext = {
|
|
97
97
|
/**
|
package/dist/workflow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,MAAM,kBAAkB,CAAC;AAK1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAKtD,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,KAAK,EACX,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,6BAA6B,EAC7B,MAAM,yBAAyB,CAAC;AAEjC,KAAK,cAAc,GAAG;IACrB,yEAAyE;IACzE,cAAc,CAAC,EAAE,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,gBAAgB,CAAC,CAAC;AAErE,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,eAAe,IAAI,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE7F,MAAM,MAAM,wBAAwB,CAAC,CAAC,SAAS,SAAS,eAAe,EAAE,IACxE,uBAAuB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEpC,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAElG;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAChC,SAAS,SAAS,SAAS,CAAC,eAAe,EAAE,GAAG,eAAe,EAAE,CAAC,EAClE,YAAY,SAAS,SAAS,kBAAkB,EAAE,GAAG,SAAS,kBAAkB,EAAE,IAC/E;IACH;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAE3B,OAAO,EAAE,CACR,KAAK,EAAE,wBAAwB,CAAC,SAAS,CAAC,EAC1C,OAAO,EAAE,eAAe,CAAC,YAAY,CAAC,KAClC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,4BAA4B,CACvC,SAAS,SAAS,SAAS,CAAC,eAAe,EAAE,GAAG,eAAe,EAAE,CAAC,EAClE,YAAY,SAAS,SAAS,kBAAkB,EAAE,IAC/C,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,UAAU,CAAC,GAAG;IACtE,QAAQ,EAAE,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,uBAAuB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;KAAE,KAAK,SAAS,CAAC;CAC/F,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,CACnB,SAAS,SAAS,SAAS,CAAC,eAAe,EAAE,GAAG,eAAe,EAAE,CAAC,GAAG,SAAS;IAC7E,eAAe;IACf,GAAG,eAAe,EAAE;CACpB,IACE;IACH,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,SAAS,CAAC;QACpB,WAAW,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;KAC5C,CAAC;IACF,OAAO,EAAE,CACR,KAAK,EAAE,wBAAwB,CAAC,SAAS,CAAC,EAC1C,OAAO,CAAC,EAAE,cAAc,KACpB,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC;CAChD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
|
package/dist/workflow.js
CHANGED
|
@@ -13,7 +13,7 @@ import { resolveRuntimeInput } from "./runtime-input.js";
|
|
|
13
13
|
import { readRunMetadata } from "./runtime-metadata.js";
|
|
14
14
|
import { createWorkflowTriggers } from "./triggers.generated.js";
|
|
15
15
|
import { connections } from "./connections.js";
|
|
16
|
-
function
|
|
16
|
+
function workflow(configuration) {
|
|
17
17
|
const triggers = typeof configuration.triggers === "function" ? configuration.triggers({ triggers: createWorkflowTriggers() }) : configuration.triggers;
|
|
18
18
|
validateConnectionRequirements(configuration.connections ?? []);
|
|
19
19
|
validateTriggerConnections(triggers, configuration.connections ?? []);
|
|
@@ -222,5 +222,5 @@ function isNodeError(error) {
|
|
|
222
222
|
}
|
|
223
223
|
export {
|
|
224
224
|
connections,
|
|
225
|
-
|
|
225
|
+
workflow
|
|
226
226
|
};
|
package/docs/BUILD.md
CHANGED
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
Each top-level TypeScript file under a capability directory must default-export the
|
|
12
12
|
corresponding capability. The filename becomes its key:
|
|
13
13
|
|
|
14
|
-
| Directory | Default export
|
|
15
|
-
| ------------------- |
|
|
16
|
-
| `src/workflows/` | `
|
|
17
|
-
| `src/syncs/` | `
|
|
18
|
-
| `src/customBlocks/` | `
|
|
14
|
+
| Directory | Default export |
|
|
15
|
+
| ------------------- | ------------------ |
|
|
16
|
+
| `src/workflows/` | `workflow(...)` |
|
|
17
|
+
| `src/syncs/` | `sync(...)` |
|
|
18
|
+
| `src/customBlocks/` | `customBlock(...)` |
|
|
19
19
|
|
|
20
20
|
```text
|
|
21
21
|
my-app/
|
package/docs/CONNECTIONS.md
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
Workflow connections declare services that a workflow needs to work properly. Connections require explicit authentication during setup before the workflow can use them. Each connection has a stable binding that links it to its configured credentials and permissions.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
import {
|
|
6
|
+
import { workflow } from "@notionhq/apps";
|
|
7
|
+
import { connections } from "@notionhq/apps/workflow";
|
|
7
8
|
import { triggers } from "@notionhq/apps/triggers";
|
|
8
9
|
|
|
9
|
-
export default
|
|
10
|
+
export default workflow({
|
|
10
11
|
name: "List work calendars",
|
|
11
12
|
description: "List calendars available through the work connection",
|
|
12
13
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -25,7 +26,7 @@ An omitted key defaults to the provider type, so `connections.calendar()` is acc
|
|
|
25
26
|
Use a trigger callback to check connection keys against the workflow’s declared providers:
|
|
26
27
|
|
|
27
28
|
```ts
|
|
28
|
-
export default
|
|
29
|
+
export default workflow({
|
|
29
30
|
name: "Support messages",
|
|
30
31
|
description: "Run when a message arrives in the configured support channel",
|
|
31
32
|
connections: [connections.slack({ key: "support" })],
|
|
@@ -42,7 +43,7 @@ export default createWorkflow({
|
|
|
42
43
|
|
|
43
44
|
The callback’s `triggers.slackMessage` accepts only Slack keys declared in `connections`. In this example, `"typo"` is a type error, and a Calendar connection named `"support"` would not satisfy a Slack trigger. Keys remain literal when you save a declaration in a variable, so the same check works with `const support = connections.slack({ key: "support" })`. Omitting the declaration key defaults to the provider name.
|
|
44
45
|
|
|
45
|
-
The callback runs once when `
|
|
46
|
+
The callback runs once when `workflow` is called. Its result is serialized as the ordinary trigger array, and the handler’s event type is inferred from those triggers. Returning a keyed trigger from an imported helper is checked too. Existing static trigger arrays remain supported and validate connection keys at runtime; use the callback for compile-time checking. Unbound triggers, including existing calls without `connectionKey`, keep their existing behavior.
|
|
46
47
|
|
|
47
48
|
Deployment creates a disabled trigger attached to that connection. Configure the account, channel or calendar, and enable the trigger through workflow setup before publishing. Redeploying preserves its configuration. The server checks the binding at publication and execution, so a trigger on another connection cannot invoke this declaration.
|
|
48
49
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@notionhq/apps",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "An SDK for building workflow apps for Notion",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
],
|
|
16
16
|
"type": "module",
|
|
17
17
|
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
18
22
|
"./context": {
|
|
19
23
|
"types": "./dist/context.d.ts",
|
|
20
24
|
"default": "./dist/context.js"
|
package/src/cli/build.test.ts
CHANGED
|
@@ -54,9 +54,7 @@ describe("buildApp", () => {
|
|
|
54
54
|
},
|
|
55
55
|
]);
|
|
56
56
|
const worker = await fs.promises.readFile(bundlePath, "utf8");
|
|
57
|
-
expect(worker).not.toMatch(
|
|
58
|
-
/custom_block|createCustomBlock|react|createRoot|NotionCustomBlock/,
|
|
59
|
-
);
|
|
57
|
+
expect(worker).not.toMatch(/custom_block|customBlock|react|createRoot|NotionCustomBlock/);
|
|
60
58
|
expect(fs.existsSync(path.join(root, ".notion/blocks.js"))).toBe(false);
|
|
61
59
|
});
|
|
62
60
|
it("names the block file when path is missing", async () => {
|
|
@@ -66,7 +64,7 @@ describe("buildApp", () => {
|
|
|
66
64
|
});
|
|
67
65
|
it("rejects a block file that exports a different capability", async () => {
|
|
68
66
|
await expect(buildApp(fixture("custom-block-wrong-tag"))).rejects.toThrow(
|
|
69
|
-
/hello.ts.*
|
|
67
|
+
/hello.ts.*customBlock/,
|
|
70
68
|
);
|
|
71
69
|
});
|
|
72
70
|
|
package/src/cli/emit-manifest.ts
CHANGED
|
@@ -233,7 +233,7 @@ export async function extractManifest(
|
|
|
233
233
|
if (!tagged || tagged._tag !== capability.tag) {
|
|
234
234
|
throw new Error(
|
|
235
235
|
`${capability.sourcePath}: default export is not a ${capability.type} — ` +
|
|
236
|
-
`files under this directory must default-export
|
|
236
|
+
`files under this directory must default-export ${capability.type === "custom_block" ? "customBlock" : capability.type}(...)`,
|
|
237
237
|
);
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -342,10 +342,6 @@ function getCapabilityRegistry(
|
|
|
342
342
|
return bundle.capabilities as Record<string, Record<string, unknown> | undefined>;
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
function capitalize(value: string): string {
|
|
346
|
-
return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
345
|
/**
|
|
350
346
|
* Throw if `value` contains anything `JSON.stringify` would silently drop or
|
|
351
347
|
* rewrite, so invalid manifest configuration fails during the build.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { createCapabilityContext } from "./context.js";
|
|
3
|
+
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
delete process.env.NOTION_API_TOKEN;
|
|
6
|
+
delete process.env.NOTION_WORKFLOW_STEP_DIRECTORY;
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe("createCapabilityContext", () => {
|
|
10
|
+
it("explains how to configure local Notion API access", () => {
|
|
11
|
+
const context = createCapabilityContext();
|
|
12
|
+
|
|
13
|
+
expect(() => context.notion.pages).toThrow(
|
|
14
|
+
"NOTION_API_TOKEN is not set. context.notion requires an API token when an app capability runs locally.",
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("explains how to grant deployed workflow access", () => {
|
|
19
|
+
process.env.NOTION_WORKFLOW_STEP_DIRECTORY = "/tmp/notion-run/steps";
|
|
20
|
+
const context = createCapabilityContext();
|
|
21
|
+
|
|
22
|
+
expect(() => context.notion.pages).toThrow(
|
|
23
|
+
"Notion API access is not configured for this deployed workflow. In Notion, open Developer Tools → Workers",
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
});
|
package/src/context.ts
CHANGED
|
@@ -13,6 +13,14 @@ const LOCAL_FIX_STEPS =
|
|
|
13
13
|
"Deployed apps receive Notion API credentials automatically. Do not push NOTION_API_TOKEN.";
|
|
14
14
|
|
|
15
15
|
function missingTokenMessage(): string {
|
|
16
|
+
if (process.env.NOTION_WORKFLOW_STEP_DIRECTORY) {
|
|
17
|
+
return (
|
|
18
|
+
"Notion API access is not configured for this deployed workflow. " +
|
|
19
|
+
"In Notion, open Developer Tools → Workers, select this workflow, and grant access to the pages or databases it uses. " +
|
|
20
|
+
"The runtime provides NOTION_API_TOKEN automatically after access is configured; do not set or push it yourself."
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
return (
|
|
17
25
|
"NOTION_API_TOKEN is not set. " +
|
|
18
26
|
"context.notion requires an API token when an app capability runs locally." +
|
package/src/custom-block.test.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { customBlock } from "./custom-block.js";
|
|
3
3
|
|
|
4
|
-
describe("
|
|
4
|
+
describe("customBlock", () => {
|
|
5
5
|
it("supports static assets without a build command", () => {
|
|
6
|
-
expect(
|
|
6
|
+
expect(customBlock({ path: "assets", static: true }).config.source).toEqual({
|
|
7
7
|
type: "static",
|
|
8
8
|
path: "assets",
|
|
9
9
|
});
|
|
@@ -11,7 +11,7 @@ describe("createCustomBlock", () => {
|
|
|
11
11
|
it.each(["//hello", "Hello", "-hello", "", "a".repeat(65)])(
|
|
12
12
|
"rejects invalid slash command %s",
|
|
13
13
|
(slashCommand) => {
|
|
14
|
-
expect(() =>
|
|
14
|
+
expect(() => customBlock({ path: "blocks/hello", slashCommand })).toThrow(
|
|
15
15
|
/slashCommand/,
|
|
16
16
|
);
|
|
17
17
|
},
|
package/src/custom-block.ts
CHANGED
|
@@ -10,9 +10,9 @@ export type CustomBlockOptions = {
|
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
/** Declare a browser project. Its filename under src/customBlocks supplies its key. */
|
|
13
|
-
export function
|
|
13
|
+
export function customBlock(options: CustomBlockOptions) {
|
|
14
14
|
if (typeof options.path !== "string" || options.path.trim() === "") {
|
|
15
|
-
throw new Error("
|
|
15
|
+
throw new Error("customBlock requires a non-empty path relative to the app root");
|
|
16
16
|
}
|
|
17
17
|
const slashCommand = options.slashCommand?.replace(/^\//, "");
|
|
18
18
|
if (slashCommand !== undefined && !/^[a-z0-9][a-z0-9_-]{0,63}$/.test(slashCommand)) {
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { customBlock } from "./custom-block.js";
|
|
2
|
+
export { customAgent } from "./notion-as-code/custom-agent.js";
|
|
3
|
+
export { database } from "./notion-as-code/database.js";
|
|
4
|
+
export { page } from "./notion-as-code/page.js";
|
|
5
|
+
export { teamspace } from "./notion-as-code/teamspace.js";
|
|
6
|
+
export { sync } from "./sync.js";
|
|
7
|
+
export { workflow } from "./workflow.js";
|
package/src/sync.ts
CHANGED
|
@@ -89,7 +89,7 @@ export type SyncConfiguration<
|
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
/** Configuration for a sync backed by a Notion-as-Code data source. */
|
|
92
|
-
type DataSourceSyncConfiguration<
|
|
92
|
+
export type DataSourceSyncConfiguration<
|
|
93
93
|
Properties extends readonly NotionAsCodeProperty[],
|
|
94
94
|
PrimaryKey extends KeyPropertyName<AppsSchemaForProperties<Properties>>,
|
|
95
95
|
State,
|
|
@@ -165,7 +165,7 @@ export function createSync<
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/** Create a sync backed by a Notion-as-Code data source. */
|
|
168
|
-
export function
|
|
168
|
+
export function sync<
|
|
169
169
|
const Properties extends readonly NotionAsCodeProperty[],
|
|
170
170
|
const PrimaryKey extends KeyPropertyName<AppsSchemaForProperties<Properties>>,
|
|
171
171
|
State = unknown,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { expectTypeOf, it } from "vitest";
|
|
2
2
|
import { triggers } from "./triggers.generated.js";
|
|
3
|
-
import { connections,
|
|
3
|
+
import { connections, workflow, type WorkflowConnection } 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()],
|
|
@@ -14,7 +14,7 @@ it("infers only the declared provider clients", () => {
|
|
|
14
14
|
},
|
|
15
15
|
});
|
|
16
16
|
const requirements = [connections.calendar(), connections.slack({ key: "support" })];
|
|
17
|
-
|
|
17
|
+
workflow({
|
|
18
18
|
name: "Multiple providers",
|
|
19
19
|
description: "Preserves providers in a separately declared array",
|
|
20
20
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -26,7 +26,7 @@ it("infers only the declared provider clients", () => {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it("exposes no providers for omitted or empty connections", () => {
|
|
29
|
-
|
|
29
|
+
workflow({
|
|
30
30
|
name: "No connections",
|
|
31
31
|
description: "Omitted",
|
|
32
32
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -34,7 +34,7 @@ it("exposes no providers for omitted or empty connections", () => {
|
|
|
34
34
|
expectTypeOf<keyof typeof context.connections>().toEqualTypeOf<never>();
|
|
35
35
|
},
|
|
36
36
|
});
|
|
37
|
-
|
|
37
|
+
workflow({
|
|
38
38
|
name: "No connections",
|
|
39
39
|
description: "Empty",
|
|
40
40
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -47,7 +47,7 @@ it("exposes no providers for omitted or empty connections", () => {
|
|
|
47
47
|
|
|
48
48
|
it("preserves literal declarations checked with satisfies", () => {
|
|
49
49
|
const requirements = [connections.slack()] satisfies readonly WorkflowConnection[];
|
|
50
|
-
|
|
50
|
+
workflow({
|
|
51
51
|
name: "Slack",
|
|
52
52
|
description: "Slack only",
|
|
53
53
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -93,10 +93,10 @@ it("checks provider keys on callback arguments and returned triggers", () => {
|
|
|
93
93
|
const fixtures = new Map(
|
|
94
94
|
cases.map((testCase) => [
|
|
95
95
|
resolve("src", `__workflow_types_${testCase.name}.ts`),
|
|
96
|
-
`import { connections,
|
|
96
|
+
`import { connections, workflow } from "./workflow.js";
|
|
97
97
|
import { triggers as globalTriggers } from "./triggers.generated.js";
|
|
98
98
|
const support = connections.slack({ key: "support" });
|
|
99
|
-
|
|
99
|
+
workflow({
|
|
100
100
|
name: "Type check", description: "Type check",
|
|
101
101
|
${testCase.connections === undefined ? "" : `connections: ${testCase.connections},`}
|
|
102
102
|
triggers: ({ triggers }) => [${testCase.trigger}],
|
package/src/workflow.test.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { afterEach, beforeEach, describe, expect, expectTypeOf, it, vi, type Moc
|
|
|
8
8
|
import { ExecutionError } from "./error.js";
|
|
9
9
|
import type { RunMetadata } from "./runtime-metadata.js";
|
|
10
10
|
import { triggers, type NotionPageCreatedEvent } from "./triggers.generated.js";
|
|
11
|
-
import { connections,
|
|
11
|
+
import { connections, workflow, type StepContext, type WorkflowContext } from "./workflow.js";
|
|
12
12
|
|
|
13
13
|
let stdoutSpy: Mock<typeof process.stdout.write>;
|
|
14
14
|
let checkpointDirectory: string | undefined;
|
|
@@ -39,7 +39,7 @@ const event = { type: "notion.page.created" } as NotionPageCreatedEvent;
|
|
|
39
39
|
|
|
40
40
|
async function createWorkflowContext(): Promise<WorkflowContext<readonly []>> {
|
|
41
41
|
let context: WorkflowContext<readonly []> | undefined;
|
|
42
|
-
const
|
|
42
|
+
const definition = workflow({
|
|
43
43
|
name: "Test workflow",
|
|
44
44
|
description: "Captures its workflow context",
|
|
45
45
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -48,7 +48,7 @@ async function createWorkflowContext(): Promise<WorkflowContext<readonly []>> {
|
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
await
|
|
51
|
+
await definition.handler(event, { concreteOutput: true });
|
|
52
52
|
|
|
53
53
|
if (!context) {
|
|
54
54
|
throw new Error("Workflow context was not created");
|
|
@@ -638,7 +638,7 @@ describe("step", () => {
|
|
|
638
638
|
|
|
639
639
|
it("resets duplicate key tracking for each workflow call", async () => {
|
|
640
640
|
const keys: string[] = [];
|
|
641
|
-
const
|
|
641
|
+
const definition = workflow({
|
|
642
642
|
name: "Reuse step key",
|
|
643
643
|
description: "Checks that a key can be reused in a new invocation",
|
|
644
644
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -654,14 +654,14 @@ describe("step", () => {
|
|
|
654
654
|
},
|
|
655
655
|
});
|
|
656
656
|
|
|
657
|
-
await
|
|
658
|
-
await
|
|
657
|
+
await definition.handler(event, { concreteOutput: true });
|
|
658
|
+
await definition.handler(event, { concreteOutput: true });
|
|
659
659
|
|
|
660
660
|
expect(keys).toEqual([workflowStepKey(["First"]), workflowStepKey(["First"])]);
|
|
661
661
|
});
|
|
662
662
|
|
|
663
663
|
it("writes step events under concreteOutput", async () => {
|
|
664
|
-
const
|
|
664
|
+
const definition = workflow({
|
|
665
665
|
name: "Log Pages",
|
|
666
666
|
description: "Logs created pages",
|
|
667
667
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -670,7 +670,7 @@ describe("step", () => {
|
|
|
670
670
|
},
|
|
671
671
|
});
|
|
672
672
|
|
|
673
|
-
await
|
|
673
|
+
await definition.handler(event, { concreteOutput: true });
|
|
674
674
|
|
|
675
675
|
expect(stdoutSpy).toHaveBeenCalledTimes(3);
|
|
676
676
|
expect(stdoutSpy.mock.calls[0]?.[0]).toEqual(
|
|
@@ -721,17 +721,17 @@ async function writeRunMetadata(overrides: Partial<RunMetadata> = {}): Promise<v
|
|
|
721
721
|
process.env.NOTION_RUN_METADATA_PATH = metadataPath;
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
-
describe("
|
|
724
|
+
describe("workflow", () => {
|
|
725
725
|
it("is tagged and exposes triggers in config", () => {
|
|
726
|
-
const
|
|
726
|
+
const definition = workflow({
|
|
727
727
|
name: "Log Pages",
|
|
728
728
|
description: "Logs created pages",
|
|
729
729
|
triggers: [triggers.notionPageCreated()],
|
|
730
730
|
handler: () => {},
|
|
731
731
|
});
|
|
732
732
|
|
|
733
|
-
expect(
|
|
734
|
-
expect(
|
|
733
|
+
expect(definition._tag).toBe("workflow");
|
|
734
|
+
expect(definition.config).toEqual({
|
|
735
735
|
name: "Log Pages",
|
|
736
736
|
description: "Logs created pages",
|
|
737
737
|
triggers: [{ type: "notion.page.created" }],
|
|
@@ -739,7 +739,7 @@ describe("createWorkflow", () => {
|
|
|
739
739
|
});
|
|
740
740
|
|
|
741
741
|
it("declares a Calendar connection requirement", () => {
|
|
742
|
-
const
|
|
742
|
+
const definition = workflow({
|
|
743
743
|
name: "Schedule Follow-up",
|
|
744
744
|
description: "Schedules a follow-up after a page is created",
|
|
745
745
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -747,12 +747,12 @@ describe("createWorkflow", () => {
|
|
|
747
747
|
handler: () => {},
|
|
748
748
|
});
|
|
749
749
|
|
|
750
|
-
expect(
|
|
750
|
+
expect(definition.config.connections).toEqual([{ type: "calendar" }]);
|
|
751
751
|
});
|
|
752
752
|
|
|
753
753
|
it("rejects duplicate connection requirements", () => {
|
|
754
754
|
expect(() =>
|
|
755
|
-
|
|
755
|
+
workflow({
|
|
756
756
|
name: "Schedule Follow-up",
|
|
757
757
|
description: "Schedules a follow-up after a page is created",
|
|
758
758
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -764,14 +764,14 @@ describe("createWorkflow", () => {
|
|
|
764
764
|
|
|
765
765
|
it("writes a success envelope after the handler runs", async () => {
|
|
766
766
|
const handler = vi.fn();
|
|
767
|
-
const
|
|
767
|
+
const definition = workflow({
|
|
768
768
|
name: "Log Pages",
|
|
769
769
|
description: "Logs created pages",
|
|
770
770
|
triggers: [triggers.notionPageCreated()],
|
|
771
771
|
handler,
|
|
772
772
|
});
|
|
773
773
|
|
|
774
|
-
await
|
|
774
|
+
await definition.handler(event);
|
|
775
775
|
|
|
776
776
|
expect(handler).toHaveBeenCalledWith(event, expect.anything());
|
|
777
777
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
@@ -784,7 +784,7 @@ describe("createWorkflow", () => {
|
|
|
784
784
|
throw new Error("Metadata directory was not created");
|
|
785
785
|
}
|
|
786
786
|
const handler = vi.fn();
|
|
787
|
-
const
|
|
787
|
+
const definition = workflow({
|
|
788
788
|
name: "Log Pages",
|
|
789
789
|
description: "Logs created pages",
|
|
790
790
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -795,27 +795,27 @@ describe("createWorkflow", () => {
|
|
|
795
795
|
await writeFile(inputPath, JSON.stringify(fileEvent));
|
|
796
796
|
process.env.NOTION_INPUT_PAYLOAD_PATH = inputPath;
|
|
797
797
|
|
|
798
|
-
await
|
|
798
|
+
await definition.handler(event, { concreteOutput: true });
|
|
799
799
|
|
|
800
800
|
expect(handler).toHaveBeenCalledWith(fileEvent, expect.anything());
|
|
801
801
|
});
|
|
802
802
|
|
|
803
803
|
it("returns the status without an envelope under concreteOutput", async () => {
|
|
804
|
-
const
|
|
804
|
+
const definition = workflow({
|
|
805
805
|
name: "Log Pages",
|
|
806
806
|
description: "Logs created pages",
|
|
807
807
|
triggers: [triggers.notionPageCreated()],
|
|
808
808
|
handler: () => {},
|
|
809
809
|
});
|
|
810
810
|
|
|
811
|
-
await expect(
|
|
811
|
+
await expect(definition.handler(event, { concreteOutput: true })).resolves.toEqual({
|
|
812
812
|
status: "success",
|
|
813
813
|
});
|
|
814
814
|
expect(stdoutSpy).not.toHaveBeenCalled();
|
|
815
815
|
});
|
|
816
816
|
|
|
817
817
|
it("writes an error envelope and throws ExecutionError on failure", async () => {
|
|
818
|
-
const
|
|
818
|
+
const definition = workflow({
|
|
819
819
|
name: "Log Pages",
|
|
820
820
|
description: "Logs created pages",
|
|
821
821
|
triggers: [triggers.notionPageCreated()],
|
|
@@ -824,7 +824,7 @@ describe("createWorkflow", () => {
|
|
|
824
824
|
},
|
|
825
825
|
});
|
|
826
826
|
|
|
827
|
-
await expect(
|
|
827
|
+
await expect(definition.handler(event)).rejects.toBeInstanceOf(ExecutionError);
|
|
828
828
|
expect(stdoutSpy).toHaveBeenCalledWith(
|
|
829
829
|
expect.stringContaining(
|
|
830
830
|
`<__notion_output__>{"_tag":"error","error":{"name":"ExecutionError","message":"Error during app execution: Error: boom"`,
|
|
@@ -836,7 +836,7 @@ describe("createWorkflow", () => {
|
|
|
836
836
|
describe("connection-bound triggers", () => {
|
|
837
837
|
it("resolves typed trigger callbacks once and preserves event inference", () => {
|
|
838
838
|
let calls = 0;
|
|
839
|
-
const
|
|
839
|
+
const definition = workflow({
|
|
840
840
|
name: "Typed triggers",
|
|
841
841
|
description: "Uses only declared provider keys",
|
|
842
842
|
connections: [connections.slack({ key: "support" }), connections.calendar()],
|
|
@@ -866,14 +866,14 @@ describe("connection-bound triggers", () => {
|
|
|
866
866
|
},
|
|
867
867
|
});
|
|
868
868
|
expect(calls).toBe(1);
|
|
869
|
-
expect(
|
|
869
|
+
expect(definition.config.triggers).toEqual([
|
|
870
870
|
{ type: "slack.message", connectionKey: "support" },
|
|
871
871
|
{ type: "calendar.event.created", connectionKey: "calendar" },
|
|
872
872
|
]);
|
|
873
873
|
});
|
|
874
874
|
|
|
875
875
|
it("preserves the binding in the manifest and infers the event", () => {
|
|
876
|
-
const
|
|
876
|
+
const definition = workflow({
|
|
877
877
|
name: "Support",
|
|
878
878
|
description: "Watch support messages",
|
|
879
879
|
connections: [connections.slack({ key: "support" })],
|
|
@@ -882,7 +882,7 @@ describe("connection-bound triggers", () => {
|
|
|
882
882
|
expectTypeOf(event.type).toEqualTypeOf<"slack.message">();
|
|
883
883
|
},
|
|
884
884
|
});
|
|
885
|
-
expect(
|
|
885
|
+
expect(definition.config.triggers).toEqual([
|
|
886
886
|
{ type: "slack.message", connectionKey: "support" },
|
|
887
887
|
]);
|
|
888
888
|
});
|
|
@@ -892,7 +892,7 @@ describe("connection-bound triggers", () => {
|
|
|
892
892
|
{ requirements: [connections.slack({ key: "other" })] },
|
|
893
893
|
])("rejects missing or incompatible declarations: %j", ({ requirements }) => {
|
|
894
894
|
expect(() =>
|
|
895
|
-
|
|
895
|
+
workflow({
|
|
896
896
|
name: "Support",
|
|
897
897
|
description: "",
|
|
898
898
|
connections: requirements,
|
|
@@ -912,7 +912,7 @@ describe("connection-bound triggers", () => {
|
|
|
912
912
|
handler() {},
|
|
913
913
|
};
|
|
914
914
|
expect(() =>
|
|
915
|
-
|
|
915
|
+
workflow({
|
|
916
916
|
...configuration,
|
|
917
917
|
triggers: [
|
|
918
918
|
triggers.slackMessage({ connectionKey: "support" }),
|
|
@@ -921,7 +921,7 @@ describe("connection-bound triggers", () => {
|
|
|
921
921
|
}),
|
|
922
922
|
).toThrow("Duplicate");
|
|
923
923
|
expect(() =>
|
|
924
|
-
|
|
924
|
+
workflow({
|
|
925
925
|
...configuration,
|
|
926
926
|
triggers: [
|
|
927
927
|
triggers.slackMessage({ connectionKey: "support" }),
|
|
@@ -933,7 +933,7 @@ describe("connection-bound triggers", () => {
|
|
|
933
933
|
it("preserves existing unkeyed helpers", () => {
|
|
934
934
|
expect(triggers.slackMessage()).toEqual({ type: "slack.message" });
|
|
935
935
|
expect(() =>
|
|
936
|
-
|
|
936
|
+
workflow({
|
|
937
937
|
name: "Existing",
|
|
938
938
|
description: "",
|
|
939
939
|
triggers: [triggers.slackMessage()],
|
package/src/workflow.ts
CHANGED
|
@@ -38,7 +38,7 @@ export type WorkflowEventForTriggers<T extends readonly WorkflowTrigger[]> =
|
|
|
38
38
|
export { connections, type WorkflowConnection, type WorkflowConnections } from "./connections.js";
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Configuration passed to {@link
|
|
41
|
+
* Configuration passed to {@link workflow}.
|
|
42
42
|
*/
|
|
43
43
|
export type WorkflowConfiguration<
|
|
44
44
|
TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]],
|
|
@@ -81,7 +81,7 @@ export type WorkflowTriggerConfiguration<
|
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* A workflow capability as returned by {@link
|
|
84
|
+
* A workflow capability as returned by {@link workflow}.
|
|
85
85
|
*
|
|
86
86
|
* Note that a workflow carries no key of its own — the build tool derives
|
|
87
87
|
* the capability key from the file the workflow is default-exported from.
|
|
@@ -115,9 +115,9 @@ export type Workflow<
|
|
|
115
115
|
* ```ts
|
|
116
116
|
* // src/workflows/onPageCreated.ts
|
|
117
117
|
* import { triggers } from "@notionhq/apps/triggers";
|
|
118
|
-
* import {
|
|
118
|
+
* import { workflow } from "@notionhq/apps/workflow";
|
|
119
119
|
*
|
|
120
|
-
* export default
|
|
120
|
+
* export default workflow({
|
|
121
121
|
* name: "Send Welcome Email",
|
|
122
122
|
* description: "Sends a welcome email when a new page is added",
|
|
123
123
|
* triggers: [triggers.notionPageCreated()],
|
|
@@ -131,18 +131,18 @@ export type Workflow<
|
|
|
131
131
|
* });
|
|
132
132
|
* ```
|
|
133
133
|
*/
|
|
134
|
-
export function
|
|
134
|
+
export function workflow<
|
|
135
135
|
const TTriggers extends readonly [
|
|
136
136
|
WorkflowTriggerForConnections<NoInfer<TConnections>>,
|
|
137
137
|
...WorkflowTriggerForConnections<NoInfer<TConnections>>[],
|
|
138
138
|
],
|
|
139
139
|
const TConnections extends readonly WorkflowConnection[] = readonly [],
|
|
140
140
|
>(configuration: WorkflowTriggerConfiguration<TTriggers, TConnections>): Workflow<TTriggers>;
|
|
141
|
-
export function
|
|
141
|
+
export function workflow<
|
|
142
142
|
const TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]],
|
|
143
143
|
const TConnections extends readonly WorkflowConnection[] = readonly [],
|
|
144
144
|
>(configuration: WorkflowConfiguration<TTriggers, TConnections>): Workflow<TTriggers>;
|
|
145
|
-
export function
|
|
145
|
+
export function workflow<
|
|
146
146
|
const TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]],
|
|
147
147
|
const TConnections extends readonly WorkflowConnection[] = readonly [],
|
|
148
148
|
>(
|