@open-everywhere/provider-notion 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +21 -0
  3. package/README.md +48 -0
  4. package/agent/channels/notion-acting-identity.ts +88 -0
  5. package/agent/channels/notion-ancestry-trust.ts +458 -0
  6. package/agent/channels/notion-api.ts +1290 -0
  7. package/agent/channels/notion-bot-user.ts +250 -0
  8. package/agent/channels/notion-catch-up.ts +339 -0
  9. package/agent/channels/notion-credentials.ts +417 -0
  10. package/agent/channels/notion-engagement.ts +372 -0
  11. package/agent/channels/notion-event-normalizer.ts +587 -0
  12. package/agent/channels/notion-identity.ts +271 -0
  13. package/agent/channels/notion-ingress-drain.ts +289 -0
  14. package/agent/channels/notion-ingress.ts +182 -0
  15. package/agent/channels/notion-message-ops.ts +140 -0
  16. package/agent/channels/notion-origin-codec.ts +38 -0
  17. package/agent/channels/notion-post-arm.ts +189 -0
  18. package/agent/channels/notion-question-return.ts +223 -0
  19. package/agent/channels/notion-read.ts +283 -0
  20. package/agent/channels/notion-scope.ts +560 -0
  21. package/agent/channels/notion-stop.ts +169 -0
  22. package/agent/channels/notion-supervisor.ts +856 -0
  23. package/agent/channels/notion-webhook-timing.ts +131 -0
  24. package/agent/channels/notion-webhook-verifier.ts +55 -0
  25. package/agent/channels/notion-webhook.ts +963 -0
  26. package/agent/channels/notion-work-search.ts +74 -0
  27. package/agent/channels/notion-work.ts +144 -0
  28. package/agent/channels/notion.ts +1242 -0
  29. package/agent/contributions.ts +39 -0
  30. package/agent/docs-generated.ts +15 -0
  31. package/agent/memory/blocks.ts +295 -0
  32. package/agent/memory/memory.ts +622 -0
  33. package/agent/provider-events.ts +198 -0
  34. package/agent/register.ts +144 -0
  35. package/agent/schedules/notion-ingress.ts +20 -0
  36. package/agent/surface-parity.ts +105 -0
  37. package/agent/tools/notion_search.ts +110 -0
  38. package/agent/tools/read_notion_comments.ts +250 -0
  39. package/agent/tools/read_notion_page.ts +351 -0
  40. package/dist/agent/channels/notion-acting-identity.d.ts +23 -0
  41. package/dist/agent/channels/notion-acting-identity.d.ts.map +1 -0
  42. package/dist/agent/channels/notion-acting-identity.js +85 -0
  43. package/dist/agent/channels/notion-acting-identity.js.map +1 -0
  44. package/dist/agent/channels/notion-ancestry-trust.d.ts +208 -0
  45. package/dist/agent/channels/notion-ancestry-trust.d.ts.map +1 -0
  46. package/dist/agent/channels/notion-ancestry-trust.js +331 -0
  47. package/dist/agent/channels/notion-ancestry-trust.js.map +1 -0
  48. package/dist/agent/channels/notion-api.d.ts +655 -0
  49. package/dist/agent/channels/notion-api.d.ts.map +1 -0
  50. package/dist/agent/channels/notion-api.js +938 -0
  51. package/dist/agent/channels/notion-api.js.map +1 -0
  52. package/dist/agent/channels/notion-bot-user.d.ts +107 -0
  53. package/dist/agent/channels/notion-bot-user.d.ts.map +1 -0
  54. package/dist/agent/channels/notion-bot-user.js +192 -0
  55. package/dist/agent/channels/notion-bot-user.js.map +1 -0
  56. package/dist/agent/channels/notion-catch-up.d.ts +64 -0
  57. package/dist/agent/channels/notion-catch-up.d.ts.map +1 -0
  58. package/dist/agent/channels/notion-catch-up.js +289 -0
  59. package/dist/agent/channels/notion-catch-up.js.map +1 -0
  60. package/dist/agent/channels/notion-credentials.d.ts +210 -0
  61. package/dist/agent/channels/notion-credentials.d.ts.map +1 -0
  62. package/dist/agent/channels/notion-credentials.js +360 -0
  63. package/dist/agent/channels/notion-credentials.js.map +1 -0
  64. package/dist/agent/channels/notion-engagement.d.ts +219 -0
  65. package/dist/agent/channels/notion-engagement.d.ts.map +1 -0
  66. package/dist/agent/channels/notion-engagement.js +283 -0
  67. package/dist/agent/channels/notion-engagement.js.map +1 -0
  68. package/dist/agent/channels/notion-event-normalizer.d.ts +194 -0
  69. package/dist/agent/channels/notion-event-normalizer.d.ts.map +1 -0
  70. package/dist/agent/channels/notion-event-normalizer.js +542 -0
  71. package/dist/agent/channels/notion-event-normalizer.js.map +1 -0
  72. package/dist/agent/channels/notion-identity.d.ts +119 -0
  73. package/dist/agent/channels/notion-identity.d.ts.map +1 -0
  74. package/dist/agent/channels/notion-identity.js +205 -0
  75. package/dist/agent/channels/notion-identity.js.map +1 -0
  76. package/dist/agent/channels/notion-ingress-drain.d.ts +66 -0
  77. package/dist/agent/channels/notion-ingress-drain.d.ts.map +1 -0
  78. package/dist/agent/channels/notion-ingress-drain.js +185 -0
  79. package/dist/agent/channels/notion-ingress-drain.js.map +1 -0
  80. package/dist/agent/channels/notion-ingress.d.ts +64 -0
  81. package/dist/agent/channels/notion-ingress.d.ts.map +1 -0
  82. package/dist/agent/channels/notion-ingress.js +130 -0
  83. package/dist/agent/channels/notion-ingress.js.map +1 -0
  84. package/dist/agent/channels/notion-message-ops.d.ts +3 -0
  85. package/dist/agent/channels/notion-message-ops.d.ts.map +1 -0
  86. package/dist/agent/channels/notion-message-ops.js +126 -0
  87. package/dist/agent/channels/notion-message-ops.js.map +1 -0
  88. package/dist/agent/channels/notion-origin-codec.d.ts +7 -0
  89. package/dist/agent/channels/notion-origin-codec.d.ts.map +1 -0
  90. package/dist/agent/channels/notion-origin-codec.js +32 -0
  91. package/dist/agent/channels/notion-origin-codec.js.map +1 -0
  92. package/dist/agent/channels/notion-post-arm.d.ts +3 -0
  93. package/dist/agent/channels/notion-post-arm.d.ts.map +1 -0
  94. package/dist/agent/channels/notion-post-arm.js +185 -0
  95. package/dist/agent/channels/notion-post-arm.js.map +1 -0
  96. package/dist/agent/channels/notion-question-return.d.ts +77 -0
  97. package/dist/agent/channels/notion-question-return.d.ts.map +1 -0
  98. package/dist/agent/channels/notion-question-return.js +183 -0
  99. package/dist/agent/channels/notion-question-return.js.map +1 -0
  100. package/dist/agent/channels/notion-read.d.ts +62 -0
  101. package/dist/agent/channels/notion-read.d.ts.map +1 -0
  102. package/dist/agent/channels/notion-read.js +257 -0
  103. package/dist/agent/channels/notion-read.js.map +1 -0
  104. package/dist/agent/channels/notion-scope.d.ts +188 -0
  105. package/dist/agent/channels/notion-scope.d.ts.map +1 -0
  106. package/dist/agent/channels/notion-scope.js +433 -0
  107. package/dist/agent/channels/notion-scope.js.map +1 -0
  108. package/dist/agent/channels/notion-stop.d.ts +48 -0
  109. package/dist/agent/channels/notion-stop.d.ts.map +1 -0
  110. package/dist/agent/channels/notion-stop.js +141 -0
  111. package/dist/agent/channels/notion-stop.js.map +1 -0
  112. package/dist/agent/channels/notion-supervisor.d.ts +462 -0
  113. package/dist/agent/channels/notion-supervisor.d.ts.map +1 -0
  114. package/dist/agent/channels/notion-supervisor.js +482 -0
  115. package/dist/agent/channels/notion-supervisor.js.map +1 -0
  116. package/dist/agent/channels/notion-webhook-timing.d.ts +35 -0
  117. package/dist/agent/channels/notion-webhook-timing.d.ts.map +1 -0
  118. package/dist/agent/channels/notion-webhook-timing.js +99 -0
  119. package/dist/agent/channels/notion-webhook-timing.js.map +1 -0
  120. package/dist/agent/channels/notion-webhook-verifier.d.ts +5 -0
  121. package/dist/agent/channels/notion-webhook-verifier.d.ts.map +1 -0
  122. package/dist/agent/channels/notion-webhook-verifier.js +53 -0
  123. package/dist/agent/channels/notion-webhook-verifier.js.map +1 -0
  124. package/dist/agent/channels/notion-webhook.d.ts +242 -0
  125. package/dist/agent/channels/notion-webhook.d.ts.map +1 -0
  126. package/dist/agent/channels/notion-webhook.js +675 -0
  127. package/dist/agent/channels/notion-webhook.js.map +1 -0
  128. package/dist/agent/channels/notion-work-search.d.ts +9 -0
  129. package/dist/agent/channels/notion-work-search.d.ts.map +1 -0
  130. package/dist/agent/channels/notion-work-search.js +69 -0
  131. package/dist/agent/channels/notion-work-search.js.map +1 -0
  132. package/dist/agent/channels/notion-work.d.ts +68 -0
  133. package/dist/agent/channels/notion-work.d.ts.map +1 -0
  134. package/dist/agent/channels/notion-work.js +126 -0
  135. package/dist/agent/channels/notion-work.js.map +1 -0
  136. package/dist/agent/channels/notion.d.ts +95 -0
  137. package/dist/agent/channels/notion.d.ts.map +1 -0
  138. package/dist/agent/channels/notion.js +1081 -0
  139. package/dist/agent/channels/notion.js.map +1 -0
  140. package/dist/agent/contributions.d.ts +32 -0
  141. package/dist/agent/contributions.d.ts.map +1 -0
  142. package/dist/agent/contributions.js +37 -0
  143. package/dist/agent/contributions.js.map +1 -0
  144. package/dist/agent/docs-generated.d.ts +3 -0
  145. package/dist/agent/docs-generated.d.ts.map +1 -0
  146. package/dist/agent/docs-generated.js +13 -0
  147. package/dist/agent/docs-generated.js.map +1 -0
  148. package/dist/agent/memory/blocks.d.ts +58 -0
  149. package/dist/agent/memory/blocks.d.ts.map +1 -0
  150. package/dist/agent/memory/blocks.js +264 -0
  151. package/dist/agent/memory/blocks.js.map +1 -0
  152. package/dist/agent/memory/memory.d.ts +157 -0
  153. package/dist/agent/memory/memory.d.ts.map +1 -0
  154. package/dist/agent/memory/memory.js +471 -0
  155. package/dist/agent/memory/memory.js.map +1 -0
  156. package/dist/agent/provider-events.d.ts +3 -0
  157. package/dist/agent/provider-events.d.ts.map +1 -0
  158. package/dist/agent/provider-events.js +196 -0
  159. package/dist/agent/provider-events.js.map +1 -0
  160. package/dist/agent/register.d.ts +5 -0
  161. package/dist/agent/register.d.ts.map +1 -0
  162. package/dist/agent/register.js +128 -0
  163. package/dist/agent/register.js.map +1 -0
  164. package/dist/agent/schedules/notion-ingress.d.ts +6 -0
  165. package/dist/agent/schedules/notion-ingress.d.ts.map +1 -0
  166. package/dist/agent/schedules/notion-ingress.js +16 -0
  167. package/dist/agent/schedules/notion-ingress.js.map +1 -0
  168. package/dist/agent/surface-parity.d.ts +3 -0
  169. package/dist/agent/surface-parity.d.ts.map +1 -0
  170. package/dist/agent/surface-parity.js +99 -0
  171. package/dist/agent/surface-parity.js.map +1 -0
  172. package/dist/agent/tools/notion_search.d.ts +56 -0
  173. package/dist/agent/tools/notion_search.d.ts.map +1 -0
  174. package/dist/agent/tools/notion_search.js +100 -0
  175. package/dist/agent/tools/notion_search.js.map +1 -0
  176. package/dist/agent/tools/read_notion_comments.d.ts +57 -0
  177. package/dist/agent/tools/read_notion_comments.d.ts.map +1 -0
  178. package/dist/agent/tools/read_notion_comments.js +236 -0
  179. package/dist/agent/tools/read_notion_comments.js.map +1 -0
  180. package/dist/agent/tools/read_notion_page.d.ts +53 -0
  181. package/dist/agent/tools/read_notion_page.d.ts.map +1 -0
  182. package/dist/agent/tools/read_notion_page.js +327 -0
  183. package/dist/agent/tools/read_notion_page.js.map +1 -0
  184. package/package.json +231 -0
  185. package/tsconfig.build.json +22 -0
  186. package/tsconfig.json +15 -0
@@ -0,0 +1,99 @@
1
+ // notion-webhook-timing — WHERE A NOTION WEBHOOK ACK'S SECONDS WENT (OPE-1929).
2
+ //
3
+ // Notion's comment route deliberately acknowledges only after the wake has been durably accepted.
4
+ // That makes every REST/store/queue wait on the path part of the webhook's observed latency. Keep
5
+ // this collector pure and injectable: production records one content-free sample, while a fake
6
+ // clock can prove the attribution without sleeping or calling a service.
7
+ export const NOTION_WEBHOOK_TIMING_ACTION = "notion.webhook_timing";
8
+ /**
9
+ * Run one whole route request and emit exactly one final sample. The caller decides when a normal
10
+ * outcome is final; any throw before that point becomes `threw` and is rethrown unchanged. Emission
11
+ * itself is telemetry and therefore fail-soft — it can never replace the HTTP result or error.
12
+ */
13
+ export async function runNotionWebhookTimed(timing, emit, operation) {
14
+ let emitted = false;
15
+ const finish = (outcome) => {
16
+ if (emitted)
17
+ return;
18
+ emitted = true;
19
+ try {
20
+ emit(timing.detail(outcome));
21
+ }
22
+ catch {
23
+ // Timing telemetry never changes the route's own result.
24
+ }
25
+ };
26
+ try {
27
+ return await operation(finish);
28
+ }
29
+ catch (err) {
30
+ finish("threw");
31
+ throw err;
32
+ }
33
+ }
34
+ function duration(start, end) {
35
+ const elapsed = end - start;
36
+ return Number.isFinite(elapsed) && elapsed > 0 ? elapsed : 0;
37
+ }
38
+ const millis = (elapsed) => Math.round(elapsed);
39
+ /**
40
+ * Create one request-scoped recorder. Phases accumulate because some operations in a phase are
41
+ * separated by gates. `dispatch` deliberately contains `eveSend` and `finalAudit`; detail() removes
42
+ * those nested spans so the published buckets are mutually exclusive rather than double-counted.
43
+ */
44
+ export function createNotionWebhookTiming(now = () => performance.now()) {
45
+ const startedAt = now();
46
+ const elapsed = new Map();
47
+ let failedPhase;
48
+ const add = (phase, start) => {
49
+ elapsed.set(phase, (elapsed.get(phase) ?? 0) + duration(start, now()));
50
+ };
51
+ return {
52
+ async measure(phase, operation) {
53
+ const start = now();
54
+ try {
55
+ return await operation();
56
+ }
57
+ catch (err) {
58
+ failedPhase ??= phase;
59
+ throw err;
60
+ }
61
+ finally {
62
+ add(phase, start);
63
+ }
64
+ },
65
+ measureSync(phase, operation) {
66
+ const start = now();
67
+ try {
68
+ return operation();
69
+ }
70
+ catch (err) {
71
+ failedPhase ??= phase;
72
+ throw err;
73
+ }
74
+ finally {
75
+ add(phase, start);
76
+ }
77
+ },
78
+ detail(outcome) {
79
+ const eveSendMs = elapsed.get("eveSend");
80
+ const finalAuditMs = elapsed.get("finalAudit");
81
+ const dispatchMs = elapsed.get("dispatch");
82
+ return {
83
+ outcome,
84
+ ...(failedPhase ? { failedPhase } : {}),
85
+ ...(elapsed.has("credential") ? { hmacCredentialMs: millis(elapsed.get("credential")) } : {}),
86
+ ...(elapsed.has("botTriggerPage") ? { botTriggerPageMs: millis(elapsed.get("botTriggerPage")) } : {}),
87
+ ...(elapsed.has("ancestorSiblingTrust") ? { ancestorSiblingTrustMs: millis(elapsed.get("ancestorSiblingTrust")) } : {}),
88
+ ...(elapsed.has("engagementDedupe") ? { engagementStoreDedupeMs: millis(elapsed.get("engagementDedupe")) } : {}),
89
+ ...(dispatchMs === undefined
90
+ ? {}
91
+ : { dispatchPreflightCatchUpMs: millis(Math.max(0, dispatchMs - (eveSendMs ?? 0) - (finalAuditMs ?? 0))) }),
92
+ ...(eveSendMs === undefined ? {} : { eveSendMs: millis(eveSendMs) }),
93
+ ...(finalAuditMs === undefined ? {} : { finalAuditMs: millis(finalAuditMs) }),
94
+ totalMs: millis(duration(startedAt, now())),
95
+ };
96
+ },
97
+ };
98
+ }
99
+ //# sourceMappingURL=notion-webhook-timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion-webhook-timing.js","sourceRoot":"","sources":["../../../agent/channels/notion-webhook-timing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { WebhookVerifier } from "@open-everywhere/core/agent/adapter-api.js";
2
+ /** The registry key — what a generic hook declares as its `source` to be verified as Notion. */
3
+ export declare const NOTION_WEBHOOK_SOURCE = "notion";
4
+ export declare const notionWebhookVerifier: WebhookVerifier;
5
+ //# sourceMappingURL=notion-webhook-verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion-webhook-verifier.d.ts","sourceRoot":"","sources":["../../../agent/channels/notion-webhook-verifier.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAElF,gGAAgG;AAChG,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAI9C,eAAO,MAAM,qBAAqB,EAAE,eAyBnC,CAAC"}
@@ -0,0 +1,53 @@
1
+ // Notion's webhook signature scheme, as a registry entry (OPE-164) — what lets a GENERIC hook
2
+ // (`POST /webhooks/<id>`) declare `source: "notion"` and be verified the way Notion signs.
3
+ //
4
+ // ZERO NEW CRYPTO. The digest is this bundle's own `verifyNotionSignature` (channels/notion-api.ts),
5
+ // the same function the native notion webhook route uses — one implementation of Notion's scheme in
6
+ // the tree, not two.
7
+ //
8
+ // THE SCHEME (https://developers.notion.com/reference/webhooks):
9
+ // X-Notion-Signature: sha256=<hex> HMAC-SHA256 of the RAW body, keyed by the ONE-TIME
10
+ // `verification_token` Notion hands over during subscription setup.
11
+ // Notion, verbatim, on why the raw bytes matter: *"Pass the raw request body exactly as it arrived
12
+ // (re-serialized JSON produces different bytes and fails verification)"*.
13
+ //
14
+ // 🔴 `signedTimestamp: false` — nothing in the signature binds freshness. Notion's payloads carry a
15
+ // timestamp FIELD, but it is not covered in a way that bounds replay, so replay against a notion
16
+ // hook is undefended and is declared as such on the reviewed allowlist.
17
+ //
18
+ // ROTATION: Notion documents no overlap window — *"If you ever rotate or recreate your webhook
19
+ // subscription, be sure to update your stored verification_token"* — so the `keys[]` list is how an
20
+ // operator gets one on our side (new token at index 0, outgoing at index 1 until the switch).
21
+ import { verifyNotionSignature } from "./notion-api.js";
22
+ /** The registry key — what a generic hook declares as its `source` to be verified as Notion. */
23
+ export const NOTION_WEBHOOK_SOURCE = "notion";
24
+ const NOTION_SIGNATURE_HEADER = "x-notion-signature";
25
+ export const notionWebhookVerifier = {
26
+ source: NOTION_WEBHOOK_SOURCE,
27
+ provider: "notion",
28
+ keyKind: "shared-secret",
29
+ // 🔴 `keyOrigin: "vendor-issued"` (OPE-186) — the key is the `verification_token` NOTION mints and
30
+ // posts to us once during subscription setup. We cannot choose it, so a secret WE minted can never
31
+ // verify a Notion delivery. This is what keeps `notion` OUT of the chat-mintable source vocabulary
32
+ // (`webhooks/source-vocabulary.ts` → `acceptsMintedSecret`). 🔴 THAT CONDITIONAL IS NO LONGER
33
+ // HYPOTHETICAL: OPE-189 added `notion-event-normalizer.ts`, so `notion` now has BOTH halves the
34
+ // vocabulary derivation looks for and `keyOrigin` is the ONLY thing excluding it. The exclusion is
35
+ // pinned live rather than asserted here — `scripts/webhook-source-vocabulary-live-test.ts` §6a
36
+ // fails any mintable source whose normalizer declares no `deliveryIdHeader`, and Notion's declares
37
+ // none (its delivery id is in the body). Flip this field and that test goes red. Only an
38
+ // OPERATOR-DECLARED hook (`loadWebhooks`, whose secret ref the operator points at the stored token)
39
+ // can use this verifier.
40
+ keyOrigin: "vendor-issued",
41
+ signedTimestamp: false,
42
+ verify({ rawBody, headers, keys }) {
43
+ const signature = headers.get(NOTION_SIGNATURE_HEADER);
44
+ if (!signature)
45
+ return { ok: false, failure: "missing-signature" };
46
+ for (const [i, key] of keys.entries()) {
47
+ if (verifyNotionSignature(key, rawBody, signature))
48
+ return { ok: true, keyIndex: i };
49
+ }
50
+ return { ok: false, failure: "signature-mismatch" };
51
+ },
52
+ };
53
+ //# sourceMappingURL=notion-webhook-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion-webhook-verifier.js","sourceRoot":"","sources":["../../../agent/channels/notion-webhook-verifier.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,2FAA2F;AAC3F,EAAE;AACF,qGAAqG;AACrG,oGAAoG;AACpG,qBAAqB;AACrB,EAAE;AACF,iEAAiE;AACjE,0FAA0F;AAC1F,sEAAsE;AACtE,mGAAmG;AACnG,0EAA0E;AAC1E,EAAE;AACF,oGAAoG;AACpG,iGAAiG;AACjG,wEAAwE;AACxE,EAAE;AACF,+FAA+F;AAC/F,oGAAoG;AACpG,8FAA8F;AAE9F,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,gGAAgG;AAChG,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAE9C,MAAM,uBAAuB,GAAG,oBAAoB,CAAC;AAErD,MAAM,CAAC,MAAM,qBAAqB,GAAoB;IACpD,MAAM,EAAE,qBAAqB;IAC7B,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,eAAe;IACxB,mGAAmG;IACnG,mGAAmG;IACnG,mGAAmG;IACnG,8FAA8F;IAC9F,gGAAgG;IAChG,mGAAmG;IACnG,+FAA+F;IAC/F,mGAAmG;IACnG,yFAAyF;IACzF,oGAAoG;IACpG,yBAAyB;IACzB,SAAS,EAAE,eAAe;IAC1B,eAAe,EAAE,KAAK;IACtB,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QAC/B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACvD,IAAI,CAAC,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;QACnE,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACtC,IAAI,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACvF,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC;IACtD,CAAC;CACF,CAAC"}
@@ -0,0 +1,242 @@
1
+ import { type FetchLike, type NotionComment, type NotionSigningKey, type NotionCallOpts, type ResolvedNotionCredential } from "./notion-api.js";
2
+ import { type NotionTrustRoots } from "./notion-ancestry-trust.js";
3
+ import { type NotionUntieredSupervisorDispatch } from "./notion-supervisor.js";
4
+ import { type NotionEngagementDeps } from "./notion-engagement.js";
5
+ import type { NotionWebhookTimingRecorder } from "./notion-webhook-timing.js";
6
+ import type { NotionCommentDispatchGuard } from "./notion-ingress-drain.js";
7
+ import { type AttachSessionForCancel, type Domain } from "@open-everywhere/core/agent/adapter-api.js";
8
+ /** The per-TURN reply target the channel snapshots at `turn.started` (see notion.ts). */
9
+ export interface NotionReplyTarget {
10
+ readonly discussionId: string;
11
+ readonly pageId?: string;
12
+ readonly workspaceId?: string;
13
+ /** The Notion integration THIS delivery verified under (OPE-467) — snapshotted with the rest of
14
+ * the target so the terminal reply posts under the credential that fetched the comment. Absent
15
+ * on a turn whose auth predates the stamp ⇒ the post falls back to the page's domain binding. */
16
+ readonly credentialId?: string;
17
+ }
18
+ /** The per-session state the channel stashes so `message.completed` can post the reply into
19
+ * the SAME discussion thread (see notion.ts's context factory). */
20
+ export interface NotionSessionState {
21
+ readonly discussionId: string | null;
22
+ readonly pageId: string | null;
23
+ readonly workspaceId: string | null;
24
+ /**
25
+ * The PER-TURN reply target, snapshotted at `turn.started` from the delivery's auth
26
+ * attributes — NOT the seeded fields above. eve applies a `send({ state })` seed only when
27
+ * it CREATES a session; a resumed (standing supervisor) session keeps its original state, so
28
+ * the seeded `discussionId` goes stale after the first wake and every later reply would land
29
+ * in the FIRST discussion. eve rewrites `session.auth.current` from the delivery's auth on
30
+ * every delivery, so the auth attributes ARE this turn's real trigger — the same snapshot
31
+ * pattern slack.ts's supervisor turn.started uses (T1.4). Mutable by design (assigned per
32
+ * turn); `undefined` = no resolvable target, and message.completed FAILS SAFE (posts nothing).
33
+ */
34
+ oeReplyTarget?: NotionReplyTarget;
35
+ /**
36
+ * True iff this session was CREATED as a UNIFIED (org, domain) supervisor session
37
+ * (notion-supervisor.ts seeds it; eve applies the seed at creation only, and a session's grain
38
+ * is fixed for its lifetime — the token shape can't change mid-generation). notion.ts's
39
+ * message.completed keys the message-tool-only silence gate on it — Notion has a WORKING
40
+ * `reply` tool on supervisor turns, so a unified turn's terminal prose is DROPPED (never
41
+ * posted) and a stray leak is audited. Absent/false on every per-doc session ⇒ the gate never
42
+ * fires ⇒ byte-identical flag-off behaviour.
43
+ */
44
+ readonly oeUnified?: boolean;
45
+ }
46
+ export interface HandleNotionDeliveryDeps {
47
+ /**
48
+ * EVERY configured Notion integration's inbound signing key, org default first
49
+ * (channels/notion-credentials.ts notionIntegrations). The gate tries each in turn and the one
50
+ * that verifies IDENTIFIES the sending integration — see gateNotionDeliveryAcross. A single-
51
+ * integration deployment passes a one-entry list and behaves exactly as it did before OPE-467.
52
+ */
53
+ readonly signingKeys: readonly NotionSigningKey[];
54
+ /** The `webhooks.allowUnverifiedNotion` setting — dev escape hatch only. */
55
+ readonly allowUnverified: boolean;
56
+ /** Resolve one Notion channel credential to its integration token AND that credential's endpoint
57
+ * rules (resolveNotionCredential). Called with the credential id the VERIFYING integration named
58
+ * (else {@link credentialForPage}), so a delivery's REST calls run under the integration that
59
+ * actually sent it. Undefined ⇒ unconfigured, and the delivery is acked without a dispatch (never
60
+ * a retry storm over a config bug).
61
+ *
62
+ * 🔴 The PAIR, never the bare key (OPE-505). Every REST call in this file spreads the result, so
63
+ * the credential's endpoint fence rides along; handing on only the token would return an unfenced
64
+ * fetch and silently disable the check on the whole webhook two-step. */
65
+ readonly credentialFor: (credentialId: string) => Promise<ResolvedNotionCredential | undefined>;
66
+ /** The credential the PAGE'S DOMAIN binds, or undefined when it binds none — see
67
+ * channels/notion-credentials.ts. It decides the credential for READS and REPLIES the agent
68
+ * initiates. On an INBOUND delivery it is only the fallback: the HMAC has already proven which
69
+ * integration sent this body, and a page id read off an unauthenticated payload never overrides
70
+ * a proof (step 5). */
71
+ readonly credentialForPage: (workspaceId: string | undefined, pageId: string | undefined) => string | undefined;
72
+ /**
73
+ * The domain registry, passed as DATA rather than as a resolved verdict (OPE-502).
74
+ *
75
+ * 🔴 THE FENCE ITSELF STAYS INSIDE THIS CORE ON PURPOSE. Step 8b's decision is a security
76
+ * boundary, so it must not be a closure a caller supplies — a caller that passed a permissive one,
77
+ * or forgot the field, would reopen the whole vector with nothing to notice it. `domains` is inert
78
+ * config, so the only thing a caller can get wrong is passing an EMPTY list, and an empty list
79
+ * fences nothing because it owns nothing. Required, never optional, for the same reason.
80
+ *
81
+ * The route hands it `getConfig().loadDomains()`, fail-soft to `[]` — the same value it already
82
+ * closes over for {@link credentialForPage} and {@link ambientEnabled}.
83
+ */
84
+ readonly domains: readonly Domain[];
85
+ /**
86
+ * The operator's declared Notion TRUST ROOTS, prepared (OPE-492) — the route passes
87
+ * `notionTrustRoots()`, the register core's `subtree: true` trust entries fill at boot (OPE-539).
88
+ *
89
+ * OPTIONAL, and that is safe where {@link HandleNotionDeliveryDeps.domains} is not: a missing
90
+ * roots list can only ever LOSE a promotion. Absent (or empty) ⇒ every page resolves `no-roots`,
91
+ * with no API call and no probe, and the delivery keeps the fail-closed `external` binding it had
92
+ * before this seam existed. `domains` is required for the opposite reason — a missing one would
93
+ * weaken a fence.
94
+ */
95
+ readonly trustRoots?: NotionTrustRoots;
96
+ /** Resolve the bot's own Notion user id FOR ONE INTEGRATION (cached per credential; env override
97
+ * or GET /v1/users/me). An unresolved id makes classifyNotionComment fail CLOSED (drop, never
98
+ * wake) — the loop guard. 🔴 It is per-integration on purpose: each Notion integration has its
99
+ * OWN bot user id, so one cached id shared across integrations would compare a reply against the
100
+ * wrong identity and break the loop guard in both directions.
101
+ * 🔴 THE CORE CALLS IT ONCE PER CONFIGURED INTEGRATION, not once per delivery (OPE-1921): step 7
102
+ * walks {@link signingKeys} to build the deployment's whole own-id set. There is deliberately no
103
+ * separate "all the ids" dep — the set is DERIVED here from a required one, so no caller can
104
+ * omit it and silently reopen the sibling loop, exactly as {@link domains} is required. */
105
+ readonly resolveBotUserId: (credentialId: string) => Promise<string | undefined>;
106
+ /** Resolve the bot's own display name for one integration (Step 4) — a judge input (the
107
+ * channel-watch preamble's "names you"), never a bypass. Optional so the core works before name
108
+ * capture is wired. */
109
+ readonly resolveBotName?: (credentialId: string) => Promise<string | undefined>;
110
+ /** Is the ambient supervisor enabled for this doc's surfaceKey? Fail-closed OFF (per-domain
111
+ * opt-in, ambientSupervisorEnabled). The WHOLE ambient path is gated behind this. */
112
+ readonly ambientEnabled: (surfaceKey: string) => boolean;
113
+ /** Resolve the doc's engagement calibration tier (memory/domain.ts engagementTierFor) for the
114
+ * judged preamble. Optional + fail-soft: absent/throwing ⇒ neutral (byte-identical). */
115
+ readonly engagementTier?: (surfaceKey: string) => "aggressive" | "neutral" | "reserved";
116
+ /** The §2.5 engagement seam's store seams (OPE-1501) — see channels/notion-engagement.ts.
117
+ * Optional: absent ⇒ the live operational store. Injected so a test drives an engaged or a
118
+ * stood-down page without one. */
119
+ readonly engagement?: NotionEngagementDeps;
120
+ /** Durable comment-level dispatch lease used only by the authenticated inbox processor. The
121
+ * synchronous development path keeps the legacy event_dedupe guard. */
122
+ readonly dispatchGuard?: NotionCommentDispatchGuard;
123
+ /** Injectable fetch (tests pass a mock; prod omits → global fetch). */
124
+ readonly fetch?: FetchLike;
125
+ readonly version?: string;
126
+ /** OVERLAY on the 429 policy every REST call of this delivery takes (OPE-1254). Live code passes
127
+ * none and gets {@link NOTION_INGRESS_RETRY} whole — the policy sized against the ingress
128
+ * function's 300 s ceiling. A test passes `{ sleep }` alone, which keeps the shipped numbers and
129
+ * only makes the waits instant. */
130
+ readonly retry?: NotionCallOpts["retry"];
131
+ /** Request-scoped, content-free latency attribution. Absent keeps non-route callers unchanged. */
132
+ readonly timing?: NotionWebhookTimingRecorder;
133
+ /** Route the classified comment to the standing doc supervisor (notion-supervisor.ts). The
134
+ * dispatch it receives is UNTIERED (OPE-596): this core holds no binding context, so the route
135
+ * leg resolves each author's tier before the supervisor core renders anything. */
136
+ readonly dispatch: (d: NotionUntieredSupervisorDispatch) => Promise<void>;
137
+ /** Called with the one-time verification token on the handshake POST (channel logs it). */
138
+ readonly onHandshakeToken?: (token: string) => void;
139
+ /** eve's cancel door, channel-agnostic (the route's own `args.attachSession`) — what the STOP LEG
140
+ * (OPE-989, step 8d below) calls through {@link routeNotionStopComment}. */
141
+ readonly attachSession: AttachSessionForCancel;
142
+ }
143
+ export interface NotionDeliveryOutcome {
144
+ readonly status: number;
145
+ readonly body: string;
146
+ readonly action: "handshake" | "rejected" | "bad-json" | "ignored" | "ambient-disabled" | "skipped-self" | "skipped-bot" | "dropped" | "dispatched" | "no-api-key" | "unresolved-page"
147
+ /** A bare `stop` comment from a genuine, distinct human (OPE-989) — the turn on this page was
148
+ * handed to `cancelAnchoredTurn`. `detail` carries the cancel outcome, never a refusal reason. */
149
+ | "stopped"
150
+ /** A plain comment on a page `stand_down` marked (OPE-1501) — suppressed by the §2.5 engagement
151
+ * registry, whatever the ambient opt-in says. `detail` carries the engagement anchor. Naming
152
+ * the agent again clears the flag, so this is never the outcome of an addressed comment. */
153
+ | "stood-down"
154
+ /** The signer does not serve the domain that owns this delivery's page (OPE-502, step 8b). */
155
+ | "scope-refused"
156
+ /** This comment id already woke a turn inside the dedupe window (OPE-1906, step 12) — a vendor
157
+ * retry, or a page two subscriptions both deliver. `detail` carries the comment id. Acked 200:
158
+ * the delivery was handled the first time, so Notion has nothing to retry. */
159
+ | "duplicate-delivery" | "error";
160
+ readonly detail?: string;
161
+ /**
162
+ * 🔴 A REAL `x-notion-signature` WAS CHECKED AGAINST A CONFIGURED SECRET (OPE-189).
163
+ *
164
+ * NOT the same as "the gate let it through". `gateNotionDelivery` also returns "accepted" when no
165
+ * secret is set AND `webhooks.allowUnverifiedNotion` is on — a local-dev hatch whose only proof is
166
+ * possession of the URL. This flag is false in that case, and the route uses it to decide whether
167
+ * the delivery may enter the ROUTING plane at all.
168
+ *
169
+ * Why the two consumers differ, deliberately: the ambient supervisor reads a comment and judges
170
+ * whether to reply, which is what the hatch exists to let you exercise on a laptop. `admitTrigger`
171
+ * fires member-authored, human-approved routines — so an unsigned acceptance must not reach it, or
172
+ * a dev hatch becomes a production capability the moment the env var is set on a real deployment.
173
+ * Same narrowing S0b applied to runtime hooks, for the same reason.
174
+ *
175
+ * False for the handshake (it arrives BEFORE any secret exists and is correctly unverified) and
176
+ * for every rejection.
177
+ */
178
+ readonly verified: boolean;
179
+ /**
180
+ * The Notion channel credential this delivery ran under (OPE-467) — the integration whose secret
181
+ * verified the signature, else (dev hatch only) the page's domain binding. Absent when the
182
+ * delivery never reached credential selection (handshake, rejection, bad json, ignored event).
183
+ * Reported so the route can audit WHICH integration served a page without a second resolution.
184
+ */
185
+ readonly credentialId?: string;
186
+ /**
187
+ * 🔴 THE INTEGRATION WHOSE SECRET VERIFIED THIS BODY (OPE-500) — the ONE authenticated identity a
188
+ * delivery carries, and a strict subset of {@link NotionDeliveryOutcome.credentialId}.
189
+ *
190
+ * NOT the same field. `credentialId` is "which integration SERVED this delivery", which falls back
191
+ * to the page binding and then to the first configured key on the dev-hatch arm — so it can name an
192
+ * integration that proved nothing. This one is set at exactly one place, from the HMAC verdict, and
193
+ * is absent whenever no secret verified (handshake, rejection, the unverified dev hatch).
194
+ *
195
+ * Present on EVERY arm past the gate, `ignored` included. The event plane needs it precisely on the
196
+ * arm the comment path drops: a `page.*` delivery never reaches credential selection, and
197
+ * `notionTriggerScopeVerdict` cannot fence a scope without knowing who signed for it.
198
+ */
199
+ readonly signerCredentialId?: string;
200
+ }
201
+ /**
202
+ * Run the whole inbound loop for one Notion webhook delivery. Returns the HTTP outcome the
203
+ * route should send AND the semantic action (for the audit row). Pure w.r.t. eve — every
204
+ * external effect is injected (fetch, resolveBotUserId, resolveBotName, ambientEnabled, dispatch,
205
+ * onHandshakeToken).
206
+ */
207
+ export declare function handleNotionDelivery(rawBody: string, signatureHeader: string | null, deps: HandleNotionDeliveryDeps): Promise<NotionDeliveryOutcome>;
208
+ /**
209
+ * Process a row that crossed {@link handleNotionDelivery}'s HMAC gate before it was committed to
210
+ * the durable ingress inbox. This is intentionally a separate entrypoint: the public route cannot
211
+ * pass an optional "already verified" flag, and the internal drain must supply the immutable signer
212
+ * identity from the row key. A deleted integration is not retargeted to another credential.
213
+ */
214
+ export declare function handleAcceptedNotionDelivery(rawBody: string, signerCredentialId: string, deps: HandleNotionDeliveryDeps): Promise<NotionDeliveryOutcome>;
215
+ /** {@link resolveDeliveryPage}'s answer. Exactly one field is set: `pageId` when the page is
216
+ * established, `reason` when it is not. A `reason` is a REFUSAL — never a page id the caller may
217
+ * substitute. */
218
+ export interface ResolvedDeliveryPage {
219
+ readonly pageId?: string;
220
+ readonly reason?: string;
221
+ }
222
+ /**
223
+ * The page a delivery's comment REALLY lives on, established from the comment Notion returned under
224
+ * the verified credential (OPE-496). The webhook's step 8 explains why the payload's own `page_id`
225
+ * may not answer this; this function is the answer that replaces it.
226
+ *
227
+ * Two shapes, one credential:
228
+ * • a PAGE-level comment carries `parent.page_id` — already the answer, and already authenticated
229
+ * (the fetch that returned it ran under the integration whose secret verified the delivery);
230
+ * • an INLINE comment carries `parent.block_id` instead, so the block's owning page is walked under
231
+ * the SAME credential ({@link resolveBlockOwningPage}, bounded at BLOCK_PARENT_MAX_HOPS).
232
+ *
233
+ * Every other outcome is a refusal with a reason: no parent at all, a parent that is neither a page
234
+ * nor a block, or a block whose walk ends anywhere but a page (a database or workspace parent, an id
235
+ * the integration cannot see, or too many hops). The caller must treat a reason as "do nothing" —
236
+ * `resolveBlockOwningPage` already states the same rule for the read fence, and both callers keep it.
237
+ *
238
+ * Exported so the delivery test can drive each shape directly, with the mock fetch counting the
239
+ * block-walk calls.
240
+ */
241
+ export declare function resolveDeliveryPage(comment: NotionComment, opts: NotionCallOpts): Promise<ResolvedDeliveryPage>;
242
+ //# sourceMappingURL=notion-webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion-webhook.d.ts","sourceRoot":"","sources":["../../../agent/channels/notion-webhook.ts"],"names":[],"mappings":"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"}