@notionhq/apps 0.0.35 → 0.0.36

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 +1 @@
1
- {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/cli/codegen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CA6CnF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAuB3F;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAWzF"}
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/cli/codegen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAqDnF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAuB3F;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CAWzF"}
@@ -22,16 +22,24 @@ export const capabilities: Record<string, Record<string, { handler: Handler }>>
22
22
  ${registry}
23
23
  };
24
24
 
25
+ // The platform dispatches a workflow's synchronous webhook verify run under its
26
+ // own invocation type. It resolves to the same capability, which tells a verify
27
+ // invocation from a trigger event by the shape of its input.
28
+ const invocationTypes: Record<string, string | undefined> = {
29
+ workflowWebhookVerify: "workflow",
30
+ };
31
+
25
32
  export async function run(
26
33
  type: string,
27
34
  key: string,
28
35
  context?: unknown,
29
36
  options?: { concreteOutput?: true },
30
37
  ): Promise<unknown> {
31
- const capability = capabilities[type]?.[key];
38
+ const capabilityType = invocationTypes[type] ?? type;
39
+ const capability = capabilities[capabilityType]?.[key];
32
40
 
33
41
  if (!capability) {
34
- throw new Error(\`Capability "\${type}/\${key}" not found\`);
42
+ throw new Error(\`Capability "\${capabilityType}/\${key}" not found\`);
35
43
  }
36
44
 
37
45
  return capability.handler(context, options);
@@ -3,7 +3,7 @@ import { type WorkflowAccess, type WorkflowAccessDeclarations, type WorkflowAcce
3
3
  import type { CapabilityContext } from "./context.js";
4
4
  import { type RunMetadata } from "./runtime-metadata.js";
5
5
  import { type WorkflowState } from "./workflow-state.js";
6
- import type { WorkflowEventMap, WorkflowTrigger, WorkflowEventCreators, WorkflowTriggerForConnections } from "./events.generated.js";
6
+ import type { WebhookTrigger, WorkflowEventMap, WorkflowTrigger, WorkflowEventCreators, WorkflowTriggerForConnections } from "./events.generated.js";
7
7
  type HandlerOptions = {
8
8
  /** Return the concrete result instead of writing the output envelope. */
9
9
  concreteOutput?: true;
@@ -98,6 +98,67 @@ export type WorkflowEvent = WorkflowEventMap[keyof WorkflowEventMap];
98
98
  export type WorkflowEventForTrigger<T extends WorkflowTrigger> = WorkflowEventMap[T["type"]];
99
99
  export type WorkflowEventForTriggers<T extends readonly WorkflowTrigger[]> = WorkflowEventForTrigger<T[number]>;
100
100
  export { connections, type WorkflowConnection, type WorkflowConnectionDeclarations, type WorkflowConnectionRequirement, type WorkflowConnections, type OAuthConfiguration, type OAuthConnection, } from "./connections.js";
101
+ /**
102
+ * The inbound HTTP request passed to a webhook verify handler.
103
+ */
104
+ export type WebhookVerifyRequest = {
105
+ /** Uppercase HTTP method. Deliveries are POSTs; GET/HEAD cover challenge probes. */
106
+ method: "GET" | "HEAD" | "POST";
107
+ /** The full webhook URL as received. */
108
+ url: string;
109
+ /** Query string parameters. */
110
+ query: Record<string, string>;
111
+ /** Request headers with lowercased names. */
112
+ headers: Record<string, string>;
113
+ /** Raw request body. Empty string for bodyless methods like GET and HEAD. */
114
+ rawBody: string;
115
+ };
116
+ /**
117
+ * The HTTP response a verify handler produces. `deliver`, when present,
118
+ * explicitly controls whether the request is enqueued for the workflow
119
+ * handler. Otherwise delivery is derived from the status: 2xx enqueues and 4xx
120
+ * does not.
121
+ */
122
+ export type WebhookVerifyResponse = {
123
+ /** Response status code. Only 2xx and 4xx statuses are allowed. */
124
+ status: number;
125
+ /** Optional response body, at most 8KB. */
126
+ body?: string;
127
+ /** Response content type. Defaults to "text/plain". */
128
+ contentType?: "application/json" | "text/plain";
129
+ /**
130
+ * Whether to enqueue the request for the workflow handler. Defaults to true
131
+ * for 2xx responses and false for 4xx responses.
132
+ */
133
+ deliver?: boolean;
134
+ };
135
+ /**
136
+ * A webhook verify handler. Runs synchronously at Notion's webhook ingress,
137
+ * before the HTTP response is sent, in the app's own sandbox — the same
138
+ * runtime as the workflow handler, with the full Node.js standard library.
139
+ * Read signing secrets from `process.env` and use `node:crypto` for
140
+ * signature checks.
141
+ *
142
+ * Keep it fast: the run must fit a small wall-clock budget (a few seconds,
143
+ * including sandbox startup), so avoid network calls — including
144
+ * `context.notion` API calls, which typically won't fit the budget.
145
+ */
146
+ export type WebhookVerifyHandler = (request: WebhookVerifyRequest, context: CapabilityContext) => WebhookVerifyResponse | Promise<WebhookVerifyResponse>;
147
+ /**
148
+ * A verify invocation as dispatched by the platform: a single `request`
149
+ * object rather than the event a workflow invocation carries.
150
+ */
151
+ export type WebhookVerifyInvocation = {
152
+ request: WebhookVerifyRequest;
153
+ };
154
+ /**
155
+ * A trigger as the manifest records it. A declared `verify` handler is flagged
156
+ * on the webhook trigger itself, which is where the platform reads it to decide
157
+ * whether to run `verify` at webhook ingress.
158
+ */
159
+ export type WorkflowManifestTrigger = WorkflowTrigger | (WebhookTrigger & {
160
+ hasVerify: true;
161
+ });
101
162
  /**
102
163
  * Configuration passed to {@link workflow}.
103
164
  */
@@ -126,6 +187,39 @@ export type WorkflowConfiguration<TTriggers extends readonly [WorkflowTrigger, .
126
187
  * Connections that must be set up before this workflow can run.
127
188
  */
128
189
  connections?: TConnections;
190
+ /**
191
+ * Optional synchronous verification handler, run at Notion's webhook
192
+ * ingress before the HTTP response is sent. Use it for providers that
193
+ * require a synchronous verification response: signature checks with
194
+ * specific status codes, challenge echoes, or handshake requests.
195
+ *
196
+ * Only workflows with an `events.webhook()` trigger may declare one.
197
+ *
198
+ * The handler controls the HTTP response. Return `deliver: true` to enqueue
199
+ * the request for the workflow handler, or `deliver: false` to answer the
200
+ * provider without enqueueing it. When omitted, 2xx enqueues and 4xx does
201
+ * not. `verify` runs in the app's own sandbox with full Node.js — read
202
+ * secrets from `process.env` and use `node:crypto` for signature checks. It
203
+ * receives the capability context as its second argument, without the run
204
+ * metadata and `step` a workflow run carries.
205
+ *
206
+ * Without `verify`, the webhook keeps the current behavior: every request
207
+ * is accepted with `202` and processed asynchronously.
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * verify: (request) => {
212
+ * const signature = createHmac("sha256", process.env.WEBHOOK_SECRET ?? "")
213
+ * .update(request.rawBody)
214
+ * .digest("hex");
215
+ * const expected = Buffer.from(`sha256=${signature}`);
216
+ * const actual = Buffer.from(request.headers["x-hub-signature-256"] ?? "");
217
+ * const verified = expected.length === actual.length && timingSafeEqual(expected, actual);
218
+ * return verified ? { status: 200 } : { status: 401, body: "Invalid signature" };
219
+ * },
220
+ * ```
221
+ */
222
+ verify?: WebhookVerifyHandler;
129
223
  handler: (event: WorkflowEventForTriggers<TTriggers>, context: WorkflowContext<TConnections, TAccess>) => Promise<void> | void;
130
224
  };
131
225
  /** Configuration that checks trigger keys against declared connections. */
@@ -148,11 +242,11 @@ export type Workflow<TTriggers extends readonly [WorkflowTrigger, ...WorkflowTri
148
242
  config: {
149
243
  name: string;
150
244
  description: string;
151
- triggers: TTriggers;
245
+ triggers: WorkflowManifestTrigger[];
152
246
  connections?: readonly WorkflowConnectionRequirement[];
153
247
  access?: WorkflowAccessRequirements;
154
248
  };
155
- handler: (event: WorkflowEventForTriggers<TTriggers>, options?: HandlerOptions) => Promise<WorkflowHandlerResult | undefined>;
249
+ handler: (input: WorkflowEventForTriggers<TTriggers> | WebhookVerifyInvocation, options?: HandlerOptions) => Promise<WorkflowHandlerResult | WebhookVerifyResponse | undefined>;
156
250
  };
157
251
  /**
158
252
  * Create a workflow capability.
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
package/dist/workflow.js CHANGED
@@ -17,6 +17,7 @@ import { resolveRuntimeInput } from "./runtime-input.js";
17
17
  import { readRunMetadata } from "./runtime-metadata.js";
18
18
  import { createWorkflowEvents } from "./events.generated.js";
19
19
  import { createWorkflowStepState } from "./workflow-state.js";
20
+ const WEBHOOK_TRIGGER_TYPE = "webhooks.webhook";
20
21
  const input = {
21
22
  text(options) {
22
23
  return { type: "text", ...options };
@@ -56,18 +57,40 @@ function workflow(configuration) {
56
57
  const connectionDeclarations = configuration.connections === void 0 ? void 0 : structuredClone(configuration.connections);
57
58
  const triggers = typeof configuration.triggers === "function" ? configuration.triggers({ events: createWorkflowEvents() }) : configuration.triggers;
58
59
  validateTriggerConnections(triggers, requirements);
60
+ if (configuration.verify !== void 0 && !triggers.some((trigger) => trigger.type === WEBHOOK_TRIGGER_TYPE)) {
61
+ throw new Error(
62
+ `Workflow "${configuration.name}" declares a verify handler but has no webhook trigger. Add events.webhook() or remove verify.`
63
+ );
64
+ }
59
65
  return {
60
66
  _tag: "workflow",
61
67
  config: {
62
68
  name: configuration.name,
63
69
  description: configuration.description,
64
- triggers,
70
+ triggers: manifestTriggers(triggers, configuration.verify !== void 0),
65
71
  ...configuration.connections === void 0 ? {} : { connections: requirements },
66
72
  ...configuration.access === void 0 ? {} : { access: accessRequirements }
67
73
  },
68
- async handler(event, options) {
74
+ async handler(input2, options) {
69
75
  try {
70
- event = await resolveRuntimeInput(event);
76
+ input2 = await resolveRuntimeInput(input2);
77
+ if (isVerifyInvocation(input2)) {
78
+ if (configuration.verify === void 0) {
79
+ throw new Error(
80
+ `Workflow "${configuration.name}" received a verify request but does not declare a verify handler`
81
+ );
82
+ }
83
+ const response = await configuration.verify(
84
+ input2.request,
85
+ createCapabilityContext()
86
+ );
87
+ if (options?.concreteOutput) {
88
+ return response;
89
+ }
90
+ writeOutput({ _tag: "success", value: response });
91
+ return void 0;
92
+ }
93
+ const event = input2;
71
94
  const runMetadata = readRunMetadata();
72
95
  const baseContext = createCapabilityContext();
73
96
  const step = createStep(runMetadata);
@@ -114,6 +137,14 @@ function workflow(configuration) {
114
137
  }
115
138
  };
116
139
  }
140
+ function manifestTriggers(triggers, hasVerify) {
141
+ return triggers.map(
142
+ (trigger) => hasVerify && trigger.type === WEBHOOK_TRIGGER_TYPE ? { ...trigger, hasVerify: true } : trigger
143
+ );
144
+ }
145
+ function isVerifyInvocation(input2) {
146
+ return typeof input2 === "object" && input2 !== null && "request" in input2;
147
+ }
117
148
  const WORKFLOW_STEP_DIRECTORY_ENV_KEY = "NOTION_WORKFLOW_STEP_DIRECTORY";
118
149
  const MAX_WORKFLOW_STEP_KEY_LENGTH = 43;
119
150
  const WORKFLOW_STEP_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notionhq/apps",
3
- "version": "0.0.35",
3
+ "version": "0.0.36",
4
4
  "description": "An SDK for building workflow apps for Notion",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -544,6 +544,24 @@ describe("buildApp", () => {
544
544
  expect(JSON.parse(await fs.promises.readFile(manifestPath, "utf8"))).toEqual(manifest);
545
545
  });
546
546
 
547
+ it("records a workflow's verify handler in the manifest", async () => {
548
+ const { manifestPath } = await buildApp(fixture("webhook-verify"));
549
+
550
+ expect(JSON.parse(await fs.promises.readFile(manifestPath, "utf8"))).toMatchObject({
551
+ capabilities: [
552
+ {
553
+ type: "workflow",
554
+ key: "onIncoming",
555
+ config: {
556
+ name: "Incoming Webhook",
557
+ description: "Verifies and processes an incoming webhook",
558
+ triggers: [{ type: "webhooks.webhook", hasVerify: true }],
559
+ },
560
+ },
561
+ ],
562
+ });
563
+ });
564
+
547
565
  it("collects relation databases and a shared pacer once", async () => {
548
566
  const { manifest } = await buildApp(fixture("shared-primary-key"));
549
567
 
@@ -20,6 +20,20 @@ describe("generateEntry", () => {
20
20
  expect(entry).toContain("export async function run(");
21
21
  });
22
22
 
23
+ it("resolves the webhook verify invocation type to the workflow registry", () => {
24
+ const entry = generateEntry([
25
+ {
26
+ type: "workflow",
27
+ tag: "workflow",
28
+ key: "onIncoming",
29
+ sourcePath: "src/workflows/onIncoming.ts",
30
+ runtime: "worker",
31
+ },
32
+ ]);
33
+
34
+ expect(entry).toContain(`workflowWebhookVerify: "workflow",`);
35
+ });
36
+
23
37
  it("registers syncs in their own capability group", () => {
24
38
  const entry = generateEntry([
25
39
  {
@@ -37,16 +37,24 @@ export const capabilities: Record<string, Record<string, { handler: Handler }>>
37
37
  ${registry}
38
38
  };
39
39
 
40
+ // The platform dispatches a workflow's synchronous webhook verify run under its
41
+ // own invocation type. It resolves to the same capability, which tells a verify
42
+ // invocation from a trigger event by the shape of its input.
43
+ const invocationTypes: Record<string, string | undefined> = {
44
+ workflowWebhookVerify: "workflow",
45
+ };
46
+
40
47
  export async function run(
41
48
  type: string,
42
49
  key: string,
43
50
  context?: unknown,
44
51
  options?: { concreteOutput?: true },
45
52
  ): Promise<unknown> {
46
- const capability = capabilities[type]?.[key];
53
+ const capabilityType = invocationTypes[type] ?? type;
54
+ const capability = capabilities[capabilityType]?.[key];
47
55
 
48
56
  if (!capability) {
49
- throw new Error(\`Capability "\${type}/\${key}" not found\`);
57
+ throw new Error(\`Capability "\${capabilityType}/\${key}" not found\`);
50
58
  }
51
59
 
52
60
  return capability.handler(context, options);
@@ -7,7 +7,7 @@ import { afterEach, beforeEach, describe, expect, expectTypeOf, it, vi, type Moc
7
7
 
8
8
  import { ExecutionError } from "./error.js";
9
9
  import type { RunMetadata } from "./runtime-metadata.js";
10
- import { events, type NotionPageCreatedEvent } from "./events.generated.js";
10
+ import { events, type NotionPageCreatedEvent, type WebhookEvent } from "./events.generated.js";
11
11
  import { customAgent } from "./notion-as-code/custom-agent.js";
12
12
  import { database } from "./notion-as-code/database.js";
13
13
  import { page } from "./notion-as-code/page.js";
@@ -17,6 +17,7 @@ import {
17
17
  input,
18
18
  workflow,
19
19
  type StepContext,
20
+ type WebhookVerifyHandler,
20
21
  type WorkflowContext,
21
22
  type WorkflowInputDate,
22
23
  type WorkflowWaitDuration,
@@ -1621,3 +1622,240 @@ describe("connection-bound triggers", () => {
1621
1622
  ).not.toThrow();
1622
1623
  });
1623
1624
  });
1625
+
1626
+ describe("workflow verify", () => {
1627
+ const verifyRequest = {
1628
+ method: "POST" as const,
1629
+ url: "https://123456.webhook.notionusercontent.com/webhooks/app/s/w/u/incoming",
1630
+ query: {},
1631
+ headers: { "x-signature": "sig" },
1632
+ rawBody: '{"challenge":"abc"}',
1633
+ };
1634
+
1635
+ it("marks the webhook trigger with hasVerify when a verify handler is set", () => {
1636
+ const incoming = workflow({
1637
+ name: "Incoming",
1638
+ description: "Processes an incoming webhook",
1639
+ triggers: [events.webhook()],
1640
+ verify: () => ({ status: 200 }),
1641
+ handler: () => {},
1642
+ });
1643
+
1644
+ expect(incoming.config).toEqual({
1645
+ name: "Incoming",
1646
+ description: "Processes an incoming webhook",
1647
+ triggers: [{ type: "webhooks.webhook", hasVerify: true }],
1648
+ });
1649
+ });
1650
+
1651
+ it("flags only the webhook trigger among a workflow's triggers", () => {
1652
+ const incoming = workflow({
1653
+ name: "Incoming",
1654
+ description: "Processes an incoming webhook",
1655
+ triggers: [events.notionPageCreated(), events.webhook()],
1656
+ verify: () => ({ status: 200 }),
1657
+ handler: () => {},
1658
+ });
1659
+
1660
+ expect(incoming.config.triggers).toEqual([
1661
+ { type: "notion.page.created" },
1662
+ { type: "webhooks.webhook", hasVerify: true },
1663
+ ]);
1664
+ });
1665
+
1666
+ it("omits hasVerify from the trigger when no verify handler is set", () => {
1667
+ const incoming = workflow({
1668
+ name: "Incoming",
1669
+ description: "Processes an incoming webhook",
1670
+ triggers: [events.webhook()],
1671
+ handler: () => {},
1672
+ });
1673
+
1674
+ expect(incoming.config.triggers).toEqual([{ type: "webhooks.webhook" }]);
1675
+ });
1676
+
1677
+ it("rejects a verify handler on a workflow without a webhook trigger", () => {
1678
+ expect(() =>
1679
+ workflow({
1680
+ name: "Log Pages",
1681
+ description: "Logs created pages",
1682
+ triggers: [events.notionPageCreated()],
1683
+ verify: () => ({ status: 200 }),
1684
+ handler: () => {},
1685
+ }),
1686
+ ).toThrow(/has no webhook trigger/);
1687
+ });
1688
+
1689
+ it("dispatches a verify invocation to the verify handler, not the workflow handler", async () => {
1690
+ const handler = vi.fn();
1691
+ const verify: WebhookVerifyHandler = (request) => ({
1692
+ status: 200,
1693
+ body: (JSON.parse(request.rawBody) as { challenge: string }).challenge,
1694
+ contentType: "text/plain",
1695
+ });
1696
+ const incoming = workflow({
1697
+ name: "Incoming",
1698
+ description: "Processes an incoming webhook",
1699
+ triggers: [events.webhook()],
1700
+ verify,
1701
+ handler,
1702
+ });
1703
+
1704
+ const response = await incoming.handler(
1705
+ { request: verifyRequest },
1706
+ { concreteOutput: true },
1707
+ );
1708
+
1709
+ expect(response).toEqual({ status: 200, body: "abc", contentType: "text/plain" });
1710
+ expect(handler).not.toHaveBeenCalled();
1711
+ });
1712
+
1713
+ it("returns an explicit delivery decision from the verify handler", async () => {
1714
+ const incoming = workflow({
1715
+ name: "Incoming",
1716
+ description: "Processes an incoming webhook",
1717
+ triggers: [events.webhook()],
1718
+ verify: () => ({ status: 200, deliver: false }),
1719
+ handler: () => {},
1720
+ });
1721
+
1722
+ const response = await incoming.handler(
1723
+ { request: verifyRequest },
1724
+ { concreteOutput: true },
1725
+ );
1726
+
1727
+ expect(response).toEqual({ status: 200, deliver: false });
1728
+ });
1729
+
1730
+ it("passes the capability context to the verify handler", async () => {
1731
+ let receivedContext: unknown;
1732
+ const incoming = workflow({
1733
+ name: "Incoming",
1734
+ description: "Processes an incoming webhook",
1735
+ triggers: [events.webhook()],
1736
+ verify: (_request, context) => {
1737
+ receivedContext = context;
1738
+ return { status: 200 };
1739
+ },
1740
+ handler: () => {},
1741
+ });
1742
+
1743
+ await incoming.handler({ request: verifyRequest }, { concreteOutput: true });
1744
+
1745
+ expect(receivedContext).toHaveProperty("notion");
1746
+ expect(receivedContext).not.toHaveProperty("step");
1747
+ });
1748
+
1749
+ it("verifies without workflow run metadata", async () => {
1750
+ delete process.env.NOTION_RUN_METADATA_PATH;
1751
+ const incoming = workflow({
1752
+ name: "Incoming",
1753
+ description: "Processes an incoming webhook",
1754
+ triggers: [events.webhook()],
1755
+ verify: () => ({ status: 200 }),
1756
+ handler: () => {},
1757
+ });
1758
+
1759
+ await expect(
1760
+ incoming.handler({ request: verifyRequest }, { concreteOutput: true }),
1761
+ ).resolves.toEqual({ status: 200 });
1762
+ });
1763
+
1764
+ it("writes the verify response as a success envelope without concreteOutput", async () => {
1765
+ const incoming = workflow({
1766
+ name: "Incoming",
1767
+ description: "Processes an incoming webhook",
1768
+ triggers: [events.webhook()],
1769
+ verify: () => ({ status: 401 }),
1770
+ handler: () => {},
1771
+ });
1772
+
1773
+ await incoming.handler({ request: verifyRequest });
1774
+
1775
+ expect(stdoutSpy).toHaveBeenCalledWith(
1776
+ expect.stringContaining('"_tag":"success","value":{"status":401}'),
1777
+ );
1778
+ });
1779
+
1780
+ it("runs in the app bundle, so verify handlers may capture module scope", async () => {
1781
+ const signingSecret = "shh";
1782
+ const incoming = workflow({
1783
+ name: "Incoming",
1784
+ description: "Processes an incoming webhook",
1785
+ triggers: [events.webhook()],
1786
+ verify: (request) => ({
1787
+ status: request.headers["x-signature"] === signingSecret ? 200 : 401,
1788
+ }),
1789
+ handler: () => {},
1790
+ });
1791
+
1792
+ const response = await incoming.handler(
1793
+ { request: { ...verifyRequest, headers: { "x-signature": "shh" } } },
1794
+ { concreteOutput: true },
1795
+ );
1796
+
1797
+ expect(response).toEqual({ status: 200 });
1798
+ });
1799
+
1800
+ it("uses a file-backed verify request instead of the inline invocation", async () => {
1801
+ if (!metadataDirectory) {
1802
+ throw new Error("Metadata directory was not created");
1803
+ }
1804
+ const payloadPath = join(metadataDirectory, "verify-input.json");
1805
+ await writeFile(
1806
+ payloadPath,
1807
+ JSON.stringify({ request: { ...verifyRequest, rawBody: '{"challenge":"file"}' } }),
1808
+ );
1809
+ process.env.NOTION_INPUT_PAYLOAD_PATH = payloadPath;
1810
+
1811
+ const incoming = workflow({
1812
+ name: "Incoming",
1813
+ description: "Processes an incoming webhook",
1814
+ triggers: [events.webhook()],
1815
+ verify: (request) => ({
1816
+ status: 200,
1817
+ body: (JSON.parse(request.rawBody) as { challenge: string }).challenge,
1818
+ }),
1819
+ handler: () => {},
1820
+ });
1821
+
1822
+ const response = await incoming.handler(
1823
+ { request: verifyRequest },
1824
+ { concreteOutput: true },
1825
+ );
1826
+
1827
+ expect(response).toEqual({ status: 200, body: "file" });
1828
+ });
1829
+
1830
+ it("still dispatches trigger events to the workflow handler when verify is configured", async () => {
1831
+ const handler = vi.fn();
1832
+ const webhookEvent = { type: "webhooks.webhook" } as WebhookEvent;
1833
+ const incoming = workflow({
1834
+ name: "Incoming",
1835
+ description: "Processes an incoming webhook",
1836
+ triggers: [events.webhook()],
1837
+ verify: () => ({ status: 200 }),
1838
+ handler,
1839
+ });
1840
+
1841
+ const result = await incoming.handler(webhookEvent, { concreteOutput: true });
1842
+
1843
+ expect(result).toEqual({ status: "success" });
1844
+ expect(handler).toHaveBeenCalledWith(webhookEvent, expect.anything());
1845
+ });
1846
+
1847
+ it("rejects a verify invocation when no verify handler is declared", async () => {
1848
+ const handler = vi.fn();
1849
+ const incoming = workflow({
1850
+ name: "Incoming",
1851
+ description: "Processes an incoming webhook",
1852
+ triggers: [events.webhook()],
1853
+ handler,
1854
+ });
1855
+
1856
+ await expect(
1857
+ incoming.handler({ request: verifyRequest }, { concreteOutput: true }),
1858
+ ).rejects.toThrow(/does not declare a verify handler/);
1859
+ expect(handler).not.toHaveBeenCalled();
1860
+ });
1861
+ });
package/src/workflow.ts CHANGED
@@ -26,6 +26,7 @@ import { readRunMetadata, type RunMetadata } from "./runtime-metadata.js";
26
26
  import { createWorkflowEvents } from "./events.generated.js";
27
27
  import { createWorkflowStepState, type WorkflowState } from "./workflow-state.js";
28
28
  import type {
29
+ WebhookTrigger,
29
30
  WorkflowEventMap,
30
31
  WorkflowTrigger,
31
32
  WorkflowEventCreators,
@@ -37,6 +38,9 @@ type HandlerOptions = {
37
38
  concreteOutput?: true;
38
39
  };
39
40
 
41
+ /** The only trigger whose deliveries a verify handler can answer. */
42
+ const WEBHOOK_TRIGGER_TYPE: WebhookTrigger["type"] = "webhooks.webhook";
43
+
40
44
  type WorkflowWaitDurationValues = {
41
45
  milliseconds?: number;
42
46
  seconds?: number;
@@ -215,6 +219,73 @@ export {
215
219
  type OAuthConnection,
216
220
  } from "./connections.js";
217
221
 
222
+ /**
223
+ * The inbound HTTP request passed to a webhook verify handler.
224
+ */
225
+ export type WebhookVerifyRequest = {
226
+ /** Uppercase HTTP method. Deliveries are POSTs; GET/HEAD cover challenge probes. */
227
+ method: "GET" | "HEAD" | "POST";
228
+ /** The full webhook URL as received. */
229
+ url: string;
230
+ /** Query string parameters. */
231
+ query: Record<string, string>;
232
+ /** Request headers with lowercased names. */
233
+ headers: Record<string, string>;
234
+ /** Raw request body. Empty string for bodyless methods like GET and HEAD. */
235
+ rawBody: string;
236
+ };
237
+
238
+ /**
239
+ * The HTTP response a verify handler produces. `deliver`, when present,
240
+ * explicitly controls whether the request is enqueued for the workflow
241
+ * handler. Otherwise delivery is derived from the status: 2xx enqueues and 4xx
242
+ * does not.
243
+ */
244
+ export type WebhookVerifyResponse = {
245
+ /** Response status code. Only 2xx and 4xx statuses are allowed. */
246
+ status: number;
247
+ /** Optional response body, at most 8KB. */
248
+ body?: string;
249
+ /** Response content type. Defaults to "text/plain". */
250
+ contentType?: "application/json" | "text/plain";
251
+ /**
252
+ * Whether to enqueue the request for the workflow handler. Defaults to true
253
+ * for 2xx responses and false for 4xx responses.
254
+ */
255
+ deliver?: boolean;
256
+ };
257
+
258
+ /**
259
+ * A webhook verify handler. Runs synchronously at Notion's webhook ingress,
260
+ * before the HTTP response is sent, in the app's own sandbox — the same
261
+ * runtime as the workflow handler, with the full Node.js standard library.
262
+ * Read signing secrets from `process.env` and use `node:crypto` for
263
+ * signature checks.
264
+ *
265
+ * Keep it fast: the run must fit a small wall-clock budget (a few seconds,
266
+ * including sandbox startup), so avoid network calls — including
267
+ * `context.notion` API calls, which typically won't fit the budget.
268
+ */
269
+ export type WebhookVerifyHandler = (
270
+ request: WebhookVerifyRequest,
271
+ context: CapabilityContext,
272
+ ) => WebhookVerifyResponse | Promise<WebhookVerifyResponse>;
273
+
274
+ /**
275
+ * A verify invocation as dispatched by the platform: a single `request`
276
+ * object rather than the event a workflow invocation carries.
277
+ */
278
+ export type WebhookVerifyInvocation = {
279
+ request: WebhookVerifyRequest;
280
+ };
281
+
282
+ /**
283
+ * A trigger as the manifest records it. A declared `verify` handler is flagged
284
+ * on the webhook trigger itself, which is where the platform reads it to decide
285
+ * whether to run `verify` at webhook ingress.
286
+ */
287
+ export type WorkflowManifestTrigger = WorkflowTrigger | (WebhookTrigger & { hasVerify: true });
288
+
218
289
  /**
219
290
  * Configuration passed to {@link workflow}.
220
291
  */
@@ -252,6 +323,40 @@ export type WorkflowConfiguration<
252
323
  */
253
324
  connections?: TConnections;
254
325
 
326
+ /**
327
+ * Optional synchronous verification handler, run at Notion's webhook
328
+ * ingress before the HTTP response is sent. Use it for providers that
329
+ * require a synchronous verification response: signature checks with
330
+ * specific status codes, challenge echoes, or handshake requests.
331
+ *
332
+ * Only workflows with an `events.webhook()` trigger may declare one.
333
+ *
334
+ * The handler controls the HTTP response. Return `deliver: true` to enqueue
335
+ * the request for the workflow handler, or `deliver: false` to answer the
336
+ * provider without enqueueing it. When omitted, 2xx enqueues and 4xx does
337
+ * not. `verify` runs in the app's own sandbox with full Node.js — read
338
+ * secrets from `process.env` and use `node:crypto` for signature checks. It
339
+ * receives the capability context as its second argument, without the run
340
+ * metadata and `step` a workflow run carries.
341
+ *
342
+ * Without `verify`, the webhook keeps the current behavior: every request
343
+ * is accepted with `202` and processed asynchronously.
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * verify: (request) => {
348
+ * const signature = createHmac("sha256", process.env.WEBHOOK_SECRET ?? "")
349
+ * .update(request.rawBody)
350
+ * .digest("hex");
351
+ * const expected = Buffer.from(`sha256=${signature}`);
352
+ * const actual = Buffer.from(request.headers["x-hub-signature-256"] ?? "");
353
+ * const verified = expected.length === actual.length && timingSafeEqual(expected, actual);
354
+ * return verified ? { status: 200 } : { status: 401, body: "Invalid signature" };
355
+ * },
356
+ * ```
357
+ */
358
+ verify?: WebhookVerifyHandler;
359
+
255
360
  handler: (
256
361
  event: WorkflowEventForTriggers<TTriggers>,
257
362
  context: WorkflowContext<TConnections, TAccess>,
@@ -283,14 +388,14 @@ export type Workflow<
283
388
  config: {
284
389
  name: string;
285
390
  description: string;
286
- triggers: TTriggers;
391
+ triggers: WorkflowManifestTrigger[];
287
392
  connections?: readonly WorkflowConnectionRequirement[];
288
393
  access?: WorkflowAccessRequirements;
289
394
  };
290
395
  handler: (
291
- event: WorkflowEventForTriggers<TTriggers>,
396
+ input: WorkflowEventForTriggers<TTriggers> | WebhookVerifyInvocation,
292
397
  options?: HandlerOptions,
293
- ) => Promise<WorkflowHandlerResult | undefined>;
398
+ ) => Promise<WorkflowHandlerResult | WebhookVerifyResponse | undefined>;
294
399
  };
295
400
 
296
401
  /**
@@ -355,21 +460,54 @@ export function workflow<
355
460
  : configuration.triggers;
356
461
  validateTriggerConnections(triggers, requirements);
357
462
 
463
+ if (
464
+ configuration.verify !== undefined &&
465
+ !triggers.some((trigger) => trigger.type === WEBHOOK_TRIGGER_TYPE)
466
+ ) {
467
+ throw new Error(
468
+ `Workflow "${configuration.name}" declares a verify handler but has no webhook trigger. ` +
469
+ `Add events.webhook() or remove verify.`,
470
+ );
471
+ }
472
+
358
473
  return {
359
474
  _tag: "workflow",
360
475
  config: {
361
476
  name: configuration.name,
362
477
  description: configuration.description,
363
- triggers,
478
+ triggers: manifestTriggers(triggers, configuration.verify !== undefined),
364
479
  ...(configuration.connections === undefined ? {} : { connections: requirements }),
365
480
  ...(configuration.access === undefined ? {} : { access: accessRequirements }),
366
481
  },
367
482
  async handler(
368
- event: WorkflowEventForTriggers<TTriggers>,
483
+ input: WorkflowEventForTriggers<TTriggers> | WebhookVerifyInvocation,
369
484
  options?: HandlerOptions,
370
- ): Promise<WorkflowHandlerResult | undefined> {
485
+ ): Promise<WorkflowHandlerResult | WebhookVerifyResponse | undefined> {
371
486
  try {
372
- event = await resolveRuntimeInput(event);
487
+ input = await resolveRuntimeInput(input);
488
+
489
+ if (isVerifyInvocation(input)) {
490
+ if (configuration.verify === undefined) {
491
+ throw new Error(
492
+ `Workflow "${configuration.name}" received a verify request but does not ` +
493
+ `declare a verify handler`,
494
+ );
495
+ }
496
+
497
+ const response = await configuration.verify(
498
+ input.request,
499
+ createCapabilityContext(),
500
+ );
501
+
502
+ if (options?.concreteOutput) {
503
+ return response;
504
+ }
505
+
506
+ writeOutput({ _tag: "success", value: response });
507
+ return undefined;
508
+ }
509
+
510
+ const event = input;
373
511
  const runMetadata = readRunMetadata();
374
512
  const baseContext = createCapabilityContext();
375
513
  const step = createStep(runMetadata);
@@ -423,6 +561,31 @@ export function workflow<
423
561
  };
424
562
  }
425
563
 
564
+ /**
565
+ * The triggers as the manifest records them. The manifest only records that a
566
+ * verify handler exists, flagged on the webhook trigger; the handler itself
567
+ * ships in the app bundle and runs via a verify invocation.
568
+ */
569
+ function manifestTriggers(
570
+ triggers: readonly WorkflowTrigger[],
571
+ hasVerify: boolean,
572
+ ): WorkflowManifestTrigger[] {
573
+ return triggers.map((trigger) =>
574
+ hasVerify && trigger.type === WEBHOOK_TRIGGER_TYPE
575
+ ? { ...trigger, hasVerify: true as const }
576
+ : trigger,
577
+ );
578
+ }
579
+
580
+ /**
581
+ * Whether an invocation is the platform's synchronous verify dispatch. The
582
+ * platform sends workflow invocations as a trigger event and verify
583
+ * invocations as a `{ request }` object, so the shape disambiguates.
584
+ */
585
+ function isVerifyInvocation(input: unknown): input is WebhookVerifyInvocation {
586
+ return typeof input === "object" && input !== null && "request" in input;
587
+ }
588
+
426
589
  /** Context passed to a workflow step. */
427
590
  export type StepContext = {
428
591
  /**