@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,264 @@
1
+ // Notion blocks → Markdown codec (PURE — no network), the read half of the Notion
2
+ // memory backing (docs/capabilities/memory.md "Notion backing"). Notion stores typed blocks,
3
+ // not raw markdown, so a domain's read-only memory page is rendered to markdown the
4
+ // agent reads. Kept separate from the API client so it's trivially unit-testable.
5
+ //
6
+ // v1 renders the common block types (headings, paragraphs, lists, to-dos, quotes,
7
+ // callouts, code, dividers, equations) with bold/italic/code inline annotations; nested
8
+ // content blocks (a toggle's or list item's children) recurse with indentation. child_page
9
+ // / child_database blocks are NOT rendered inline — they're pulled as separate pages by
10
+ // the walker (memory.ts). Unknown TEXT block types degrade to their plain text.
11
+ //
12
+ // Rich blocks that can't be faithfully rendered to markdown (image, table, embed, …) are
13
+ // NOT silently dropped — they become a typed PLACEHOLDER carrying the block `type` + `id`
14
+ // (+ a caption/url hint when cheap), telling the agent to fetch that block by id via the
15
+ // Notion tools. So the 95% text stays clean and the rare rich block escalates to the tool
16
+ // by id — no silent data loss. (docs/capabilities/memory.md "rich-block placeholders".)
17
+ //
18
+ // The WRITE half is {@link blocksFromMarkdown} (OPE-70) — markdown lines → the block payloads
19
+ // Notion's own block-append API takes. It is deliberately NOT a general markdown parser: it maps
20
+ // the shapes `renderBlocks` above emits, and it PROVES each batch by rendering the blocks it built
21
+ // back through `renderBlocks`, refusing any difference. So the codec's two halves cannot drift.
22
+ //
23
+ // 🔴 THE PROOF IS AGAINST THIS CODEC, NOT AGAINST NOTION. It compares what we SEND with what
24
+ // `renderBlocks` makes of it; it never sees what the vendor stores or returns. If Notion normalises
25
+ // a payload we send, the divergence shows up on the next pull as an append-only refusal — loud, but
26
+ // after the fact. No offline tier can close that gap; only a live append can.
27
+ /** Block types that are SUB-PAGES, not inline content. */
28
+ export const PAGE_BLOCK_TYPES = new Set(["child_page", "child_database"]);
29
+ /**
30
+ * Rich / non-text block types that markdown can't faithfully carry → rendered as a typed
31
+ * placeholder (type + id + hint) instead of being dropped. `table` is here too: its rows
32
+ * (`table_row` children) aren't rendered, so we point the agent at the source. The agent
33
+ * fetches the real block BY ID via the Notion tools when it needs it.
34
+ */
35
+ const PLACEHOLDER_BLOCK_TYPES = new Set([
36
+ "image", "video", "audio", "file", "pdf", "embed", "bookmark", "link_preview", "table", "unsupported",
37
+ ]);
38
+ /** A cheap one-line hint for a placeholder: a caption or a url, when present. */
39
+ function placeholderHint(block) {
40
+ const pl = block[block.type];
41
+ if (!pl)
42
+ return "";
43
+ const cap = pl.caption && pl.caption.length > 0 ? renderRich(pl.caption) : "";
44
+ if (cap)
45
+ return ` "${cap}"`;
46
+ if (typeof pl.url === "string" && pl.url.length > 0)
47
+ return ` (${pl.url})`;
48
+ return "";
49
+ }
50
+ /** The placeholder line for an un-renderable rich block — carries type + id + how to fetch. */
51
+ function placeholderLine(block, indent) {
52
+ const id = typeof block.id === "string" && block.id.length > 0 ? ` id=${block.id}` : "";
53
+ return `${indent}> ⛏ [notion:${block.type}${id}]${placeholderHint(block)} — rich block not rendered; fetch by id via the Notion tools.`;
54
+ }
55
+ function renderRich(rich, resolve) {
56
+ if (!rich)
57
+ return "";
58
+ return rich
59
+ .map((rt) => {
60
+ // A page mention/link → rewrite to the on-disk file (when it's in this subtree).
61
+ if (resolve && rt.type === "mention" && rt.mention?.page?.id) {
62
+ const target = resolve(rt.mention.page.id);
63
+ if (target)
64
+ return `[${rt.plain_text || target.title}](${target.path})`;
65
+ }
66
+ let t = rt.plain_text ?? rt.text?.content ?? "";
67
+ const a = rt.annotations ?? {};
68
+ if (a.code)
69
+ t = `\`${t}\``;
70
+ if (a.bold)
71
+ t = `**${t}**`;
72
+ if (a.italic)
73
+ t = `*${t}*`;
74
+ return t;
75
+ })
76
+ .join("");
77
+ }
78
+ function payload(block) {
79
+ return block[block.type] ?? {};
80
+ }
81
+ /** Render one block (with its nested children) to markdown lines. */
82
+ function renderBlock(block, depth, resolve) {
83
+ const indent = " ".repeat(depth);
84
+ // Rich/non-text block we can't faithfully render → typed placeholder, and DON'T recurse
85
+ // its children (e.g. a table's rows would render as junk). The agent fetches it by id.
86
+ if (PLACEHOLDER_BLOCK_TYPES.has(block.type))
87
+ return [placeholderLine(block, indent)];
88
+ const p = payload(block);
89
+ const rich = renderRich(p.rich_text, resolve);
90
+ const lines = [];
91
+ switch (block.type) {
92
+ case "link_to_page": {
93
+ // A standalone link to another page → an on-disk link when it's in this subtree.
94
+ const pid = block.link_to_page?.page_id;
95
+ const target = pid && resolve ? resolve(pid) : undefined;
96
+ if (target)
97
+ lines.push(`${indent}[${target.title}](${target.path})`);
98
+ else if (pid)
99
+ lines.push(`${indent}(link to a page outside this memory)`);
100
+ break;
101
+ }
102
+ case "heading_1":
103
+ lines.push(`# ${rich}`);
104
+ break;
105
+ case "heading_2":
106
+ lines.push(`## ${rich}`);
107
+ break;
108
+ case "heading_3":
109
+ lines.push(`### ${rich}`);
110
+ break;
111
+ case "bulleted_list_item":
112
+ lines.push(`${indent}- ${rich}`);
113
+ break;
114
+ case "numbered_list_item":
115
+ lines.push(`${indent}1. ${rich}`);
116
+ break;
117
+ case "to_do":
118
+ lines.push(`${indent}- [${p.checked ? "x" : " "}] ${rich}`);
119
+ break;
120
+ case "toggle":
121
+ lines.push(`${indent}- ${rich}`);
122
+ break;
123
+ case "quote":
124
+ case "callout":
125
+ lines.push(`> ${rich}`);
126
+ break;
127
+ case "code":
128
+ lines.push("```" + (p.language ?? ""), rich, "```");
129
+ break;
130
+ case "equation": {
131
+ // Notion equation blocks carry `expression` (KaTeX), not rich_text — render losslessly.
132
+ const expr = block.equation?.expression ?? rich;
133
+ lines.push(`${indent}$$ ${expr} $$`);
134
+ break;
135
+ }
136
+ case "divider":
137
+ lines.push("---");
138
+ break;
139
+ default:
140
+ if (rich)
141
+ lines.push(`${indent}${rich}`);
142
+ break;
143
+ }
144
+ // Recurse into nested content children (list nesting, toggles). Page children are
145
+ // excluded here — the walker pulls them as separate files.
146
+ if (block.children) {
147
+ const nestDepth = block.type === "bulleted_list_item" || block.type === "numbered_list_item" || block.type === "to_do" || block.type === "toggle" ? depth + 1 : depth;
148
+ for (const child of block.children) {
149
+ if (PAGE_BLOCK_TYPES.has(child.type))
150
+ continue;
151
+ lines.push(...renderBlock(child, nestDepth, resolve));
152
+ }
153
+ }
154
+ return lines;
155
+ }
156
+ /**
157
+ * Render a page's top-level content blocks to a markdown document. `resolve` (optional)
158
+ * rewrites page mentions / link_to_page blocks to on-disk relative links.
159
+ */
160
+ export function renderBlocks(blocks, resolve) {
161
+ const out = [];
162
+ for (const b of blocks) {
163
+ if (PAGE_BLOCK_TYPES.has(b.type))
164
+ continue;
165
+ out.push(...renderBlock(b, 0, resolve));
166
+ }
167
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trim() + "\n";
168
+ }
169
+ /**
170
+ * The markdown lines one page's rendered content carries, with blank lines dropped and trailing
171
+ * whitespace trimmed. THE COMPARISON UNIT for the write path (memory.ts).
172
+ *
173
+ * Blank lines are dropped because Notion has no blank-line block: a blank line cannot survive a
174
+ * round trip through `renderBlocks`, so counting one as a difference would make every write look
175
+ * like an un-expressible edit.
176
+ */
177
+ export function contentLines(markdown) {
178
+ return markdown
179
+ .split("\n")
180
+ .map((line) => line.replace(/\s+$/, ""))
181
+ .filter((line) => line.length > 0);
182
+ }
183
+ /** Notion's per-`rich_text`-object content cap. A longer line is split across several objects,
184
+ * which `renderRich` re-joins with no separator — so the split is invisible on the way back. */
185
+ const MAX_RICH_TEXT = 2000;
186
+ /** The wire shape for a plain, unannotated string: `text.content`, which {@link renderBlocks}
187
+ * reads back through its `rt.text?.content` fallback. */
188
+ function plainRich(content) {
189
+ if (content.length === 0)
190
+ return [];
191
+ const out = [];
192
+ for (let i = 0; i < content.length; i += MAX_RICH_TEXT) {
193
+ out.push({ type: "text", text: { content: content.slice(i, i + MAX_RICH_TEXT) } });
194
+ }
195
+ return out;
196
+ }
197
+ function mkBlock(type, payload) {
198
+ return { object: "block", type, [type]: payload };
199
+ }
200
+ /** One markdown line → the block Notion should store for it. */
201
+ function blockForLine(line) {
202
+ let m;
203
+ if ((m = line.match(/^### (.*)$/)))
204
+ return mkBlock("heading_3", { rich_text: plainRich(m[1]) });
205
+ if ((m = line.match(/^## (.*)$/)))
206
+ return mkBlock("heading_2", { rich_text: plainRich(m[1]) });
207
+ if ((m = line.match(/^# (.*)$/)))
208
+ return mkBlock("heading_1", { rich_text: plainRich(m[1]) });
209
+ // Exactly the two markers `renderBlocks` emits. `- [X] x` deliberately does NOT match: Notion has
210
+ // no capital-X to-do state, so storing it as one would read back as `- [x] x`. It falls through to
211
+ // the paragraph arm below, which keeps the line verbatim.
212
+ if ((m = line.match(/^- \[([ x])\] (.*)$/))) {
213
+ return mkBlock("to_do", { rich_text: plainRich(m[2]), checked: m[1] === "x" });
214
+ }
215
+ if ((m = line.match(/^- (.*)$/)))
216
+ return mkBlock("bulleted_list_item", { rich_text: plainRich(m[1]) });
217
+ if ((m = line.match(/^1\. (.*)$/)))
218
+ return mkBlock("numbered_list_item", { rich_text: plainRich(m[1]) });
219
+ if ((m = line.match(/^> (.*)$/)))
220
+ return mkBlock("quote", { rich_text: plainRich(m[1]) });
221
+ if (line === "---")
222
+ return mkBlock("divider", {});
223
+ // Everything else — including an indented list line, a code fence and a rich-block placeholder —
224
+ // becomes a paragraph carrying the line VERBATIM. `renderBlocks` renders a top-level paragraph as
225
+ // its own text, so the markdown reads back unchanged even where the Notion block type is coarser.
226
+ return mkBlock("paragraph", { rich_text: plainRich(line) });
227
+ }
228
+ /**
229
+ * Markdown lines → the blocks Notion's block-append API takes, PROVEN to read back unchanged.
230
+ *
231
+ * 🔴 THE ROUND-TRIP CHECK IS THE CONTRACT, not a nicety. Memory that reads back different from what
232
+ * was written is silent corruption of the agent's own learned facts, and it would surface a whole
233
+ * session later as a mangled memory file with no error anywhere. So the blocks are rendered back
234
+ * through {@link renderBlocks} and any difference THROWS — the write is refused rather than landed.
235
+ *
236
+ * `lines` must already be {@link contentLines} output (no blank lines, no trailing whitespace).
237
+ *
238
+ * THE ANCHOR BLOCK is why the check renders one extra line and drops it. `renderBlocks` trims the
239
+ * whole document's edges, which would eat the leading indent of an INDENTED FIRST LINE (a nested
240
+ * bullet is a normal thing to append) and report a false difference. An appended batch is never the
241
+ * document's first line in reality — it lands after the page's existing blocks — so the check
242
+ * renders it in that position. The one case where reality matches the trim is an append onto an
243
+ * EMPTY page: there an indented first line does come back de-indented, and the NEXT write refuses
244
+ * loudly rather than papering over it.
245
+ */
246
+ export function blocksFromMarkdown(lines) {
247
+ const blocks = lines.map(blockForLine);
248
+ const anchor = mkBlock("paragraph", { rich_text: plainRich("anchor") });
249
+ const back = contentLines(renderBlocks([anchor, ...blocks])).slice(1);
250
+ const at = back.findIndex((line, i) => line !== lines[i]);
251
+ if (back.length !== lines.length || at !== -1) {
252
+ const i = at === -1 ? Math.min(back.length, lines.length) : at;
253
+ throw new Error(`notion memory: line ${i + 1} cannot be stored as a Notion block without changing it ` +
254
+ `(would read back as ${JSON.stringify(back[i] ?? "(nothing)")}, not ${JSON.stringify(lines[i] ?? "(nothing)")}). ` +
255
+ `The write is refused rather than saved in a form the next read would report differently.`);
256
+ }
257
+ return blocks;
258
+ }
259
+ /** The title of a child_page / child_database block (for the memory file path). */
260
+ export function pageTitle(block) {
261
+ const cp = (block.child_page ?? block.child_database);
262
+ return cp?.title?.trim() || "untitled";
263
+ }
264
+ //# sourceMappingURL=blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../../agent/memory/blocks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ import { type MemoryProvider, type MemoryAccess, type MemorySilo, type CredentialEndpointRules, type RetryPolicy } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type BlockNode } from "./blocks.js";
3
+ /**
4
+ * The ORG-DEFAULT memory credential id — the ROLE a domain override replaces, and the role name a
5
+ * `credentials` binding must name (`{ connector: "notion", credential: "memory", use: "<id>" }`).
6
+ *
7
+ * It is a SEPARATE role from the channel plumbing key on purpose. An operator may share a domain's
8
+ * BRAIN page tree with one integration and its WORK pages with another, and `Domain.credentials` is
9
+ * keyed on the role exactly so that stays expressible.
10
+ */
11
+ export declare const NOTION_MEMORY_CREDENTIAL = "memory";
12
+ export type HttpFetch = (url: string, init: {
13
+ method: string;
14
+ headers: Record<string, string>;
15
+ body?: string;
16
+ }) => Promise<{
17
+ ok: boolean;
18
+ status: number;
19
+ text(): Promise<string>;
20
+ json(): Promise<unknown>;
21
+ }>;
22
+ /** Minimal Notion REST client — lists a block's children (paginated) and appends new ones.
23
+ *
24
+ * `endpoints` (OPE-505) is the credential's declared endpoint narrowing, carried alongside the
25
+ * token so the fence travels with it — see {@link resolveNotionMemoryCredential}, the ONLY
26
+ * resolver, which returns the pair rather than a bare token for exactly this reason.
27
+ *
28
+ * 429/`Retry-After` BACKOFF (OPE-1255): `children` honours a 429 through `withRetryAfterLoose` —
29
+ * the same shared primitive `channels/notion-api.ts`'s `notionFetch` uses, adapted for `HttpFetch`'s
30
+ * response shape, which carries no `headers` accessor of its own. This was the ONE Notion transport
31
+ * OPE-1233 left uncovered — see `docs/extending/provider-rate-limits.md`. */
32
+ export declare class NotionClient {
33
+ private readonly token;
34
+ private readonly apiBase;
35
+ /** Tightens or drives the 429 backoff (OPE-1255) — a test injects a stub `sleep`; omitted
36
+ * takes the shared defaults from `channels/rate-limit-retry.ts`. */
37
+ private readonly retry?;
38
+ private readonly fetchFn;
39
+ constructor(token: string, fetchFn?: HttpFetch, apiBase?: string, endpoints?: CredentialEndpointRules,
40
+ /** Tightens or drives the 429 backoff (OPE-1255) — a test injects a stub `sleep`; omitted
41
+ * takes the shared defaults from `channels/rate-limit-retry.ts`. */
42
+ retry?: RetryPolicy | undefined);
43
+ children(blockId: string): Promise<BlockNode[]>;
44
+ /**
45
+ * APPEND blocks to the end of a page (or of any block that takes children) — Notion's own
46
+ * `PATCH /v1/blocks/{id}/children`, the write half of this backing (OPE-70).
47
+ *
48
+ * It rides the SAME guarded fetch the read does, so a credential narrowed to `GET` refuses the
49
+ * append before it is dispatched, and it carries the same 429 backoff. Batched at Notion's
50
+ * 100-children cap; a batch that fails THROWS, so a partial append surfaces as a failed persist
51
+ * rather than a success line over lost bytes.
52
+ */
53
+ appendChildren(blockId: string, children: readonly BlockNode[]): Promise<void>;
54
+ }
55
+ export interface NotionMemoryDeps {
56
+ /**
57
+ * WHICH Notion integration a read runs under, from the calling domain (OPE-485). Pure and
58
+ * synchronous, because it is also half the cache key. Omitted ⇒ every read uses the org default.
59
+ */
60
+ credentialFor?(access?: MemoryAccess): string;
61
+ client(silo: MemorySilo, credentialId: string): NotionClient | Promise<NotionClient>;
62
+ }
63
+ /**
64
+ * Build the Notion memory provider. `deps.client(silo, credentialId)` yields a client for a silo
65
+ * under one integration's token. Reads are cached for TTL_MS — a curated baseline changes rarely,
66
+ * and the subtree pull is several API calls.
67
+ *
68
+ * 🔴 THE CACHE KEY CARRIES THE CREDENTIAL AND THE SELECTION, never the root page alone. Two
69
+ * integrations may both be shared a page and see DIFFERENT subtrees of it, because Notion shares per
70
+ * page tree; and two silos may name one page under one integration and select different subsets of
71
+ * it. Keying on the page alone let the first reader's files serve the second — the cross-domain read
72
+ * the per-domain credential exists to prevent, and the subset leak `recursive`/`select` exists to
73
+ * prevent. See {@link cacheKeyFor}.
74
+ */
75
+ export declare function makeNotionProvider(deps: NotionMemoryDeps): MemoryProvider;
76
+ /**
77
+ * One resolved Notion memory credential: the token to call with, PAIRED WITH the endpoint rules
78
+ * (OPE-505) that token may be used inside. Build it with {@link resolveNotionMemoryCredential} —
79
+ * spread into a {@link NotionClient} constructor call, never assembled by hand.
80
+ *
81
+ * 🔴 THERE IS DELIBERATELY NO TOKEN-ONLY RESOLVER. A caller holding a bare token can only build an
82
+ * UNFENCED `NotionClient` (`guardHttpFetch` returns the base fetch by identity when handed no
83
+ * rules), so a resolver that returned the string alone would silently disable the check on
84
+ * whichever call site used it — the same failure mode `notion-api.ts`'s `resolveNotionCredential`
85
+ * exists to close on the channel-plumbing path.
86
+ */
87
+ export interface ResolvedNotionMemoryCredential {
88
+ readonly token: string;
89
+ /** The credential's declared endpoint narrowing, or undefined when it declares none. */
90
+ readonly endpoints?: CredentialEndpointRules;
91
+ }
92
+ /**
93
+ * The Notion credential ONE memory read runs under — the org default, or a bound domain's own
94
+ * integration — together with its endpoint rules. THE ONLY way to resolve a Notion memory
95
+ * credential.
96
+ *
97
+ * TWO PATHS, and the difference is the whole rule (OPE-467, applied to memory by OPE-485):
98
+ * • `credentialId` IS the org-default role ⇒ the deployment key, resolved through the explicit
99
+ * broker + ref stamp `registerNotionMemory` carries. Unchanged behaviour for every deployment
100
+ * that binds nothing, which is nearly all of them. Its endpoint rules come from the SAME-named
101
+ * `"memory"` entry in the registered provider set (agent/access/providers.ts) — that entry's
102
+ * `secretRef` is not what this path reads (see the comment there), but its `endpoints` is, so
103
+ * the org-default read is narrowed exactly as the entry declares.
104
+ * • `credentialId` is a BOUND domain's own credential ⇒ that `ConnectorCredential`'s own
105
+ * `secretRef` + `broker` + `endpoints`, resolved through the same seam `channels/notion-api.ts`
106
+ * uses.
107
+ *
108
+ * 🔴 A BOUND DOMAIN NEVER FALLS BACK TO THE ORG KEY. When the named credential is absent from the
109
+ * provider set, or carries no `secretRef`, this THROWS. Quietly serving the deployment key there
110
+ * would hand the domain the exact integration it was bound away from, which is the isolation the
111
+ * binding was created to buy. `assertDomainCredentialsResolvable` already refuses such a config at
112
+ * boot, so this throw is the second line, not the first.
113
+ */
114
+ export declare function resolveNotionMemoryCredential(credentialId: string, broker: string, secretRef: string): Promise<ResolvedNotionMemoryCredential>;
115
+ /**
116
+ * THE PRODUCTION WIRING of the credential seam, as a value — the deps {@link registerNotionMemory}
117
+ * registers. It is exported so a test drives the REAL wiring with only the HTTP call replaced,
118
+ * rather than restating `credentialFor` and getting a green from its own copy of the rule.
119
+ *
120
+ * `fetchFn` is the ONLY injected part. Leave it undefined in production and `NotionClient` uses
121
+ * `globalThis.fetch`.
122
+ */
123
+ export declare function notionMemoryDeps(secretRef: string, broker: string, fetchFn?: HttpFetch): NotionMemoryDeps;
124
+ /**
125
+ * Register the Notion memory backing, and DECLARE it as a connector-owned memory capability
126
+ * (OPE-390) so the prefetch invariant applies: a domain may only project a Notion subtree if it
127
+ * holds the `notion` connector grant. Memory rides the same route as connector access.
128
+ *
129
+ * MODE `"materialise"` — the DEFAULT posture: the files are a read-only PROJECTION, not the source
130
+ * of truth. The subtree is pulled to Markdown, chmod-locked in the sandbox, and the banner routes
131
+ * writes to Notion's own connector ops. A silo the author declares WRITABLE opts out of that
132
+ * posture per silo and persists through the append path above (OPE-70); the mode names what a
133
+ * Notion silo is unless its author says otherwise, and it stays the recommended shape.
134
+ *
135
+ * SUBJECT `"app-principal"` — structurally pinned (memory/connector-memory.ts). Materialisation is
136
+ * host-side at session.started, outside any session and any approval flow, and a shared domain
137
+ * brain must never be projected through one person's user-subject OAuth token: doing so would bake
138
+ * their personal access into a cache every session in the domain then reads.
139
+ *
140
+ * CREDENTIAL (OPE-485, completing the symmetry ruling's credential half). The domain that OWNS the
141
+ * silo picks the integration, and a domain that binds none uses the org default — the same one rule
142
+ * `channels/notion-credentials.ts` states for the channel plane. The seam that carries the domain is
143
+ * `MemoryAccess` (core `memory/provider.ts`); this backing turns it into a credential id with
144
+ * `domainCredentialId(access.domain, "notion", "memory")`.
145
+ *
146
+ * The ORG DEFAULT still resolves through its explicit home credential BROKER (`getSecretVia`) —
147
+ * `"db"` + `db:notion:memory` (OPE-408 step 2, re-stamped from `"env"` + `NOTION_TOKEN`),
148
+ * overridable via `OE_NOTION_SECRET_BROKER`/`OE_NOTION_SECRET_REF`. A BOUND domain resolves its own
149
+ * `ConnectorCredential` instead, through the same `findConnectorCredential` → `getSecretVia` seam the
150
+ * channel key uses, and FAILS CLOSED — see {@link resolveNotionMemoryCredential}.
151
+ *
152
+ * Resolution stays LAZY (per read, inside makeNotionProvider's client factory): registering is cheap
153
+ * and side-effect-free, and a missing secret fails loud at read time only when a `notion` silo is
154
+ * actually used.
155
+ */
156
+ export declare function registerNotionMemory(secretRef?: string, broker?: string): void;
157
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../agent/memory/memory.ts"],"names":[],"mappings":"AAqCA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,YAAY,EAQjB,KAAK,UAAU,EAOf,KAAK,uBAAuB,EAE5B,KAAK,WAAW,EACjB,MAAM,4CAA4C,CAAC;AAGpD,OAAO,EAML,KAAK,SAAS,EAGf,MAAM,aAAa,CAAC;AAQrB;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAQjD,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KACrE,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AA4BjG;;;;;;;;;6EAS6E;AAC7E,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB;yEACqE;IACrE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IATzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IAEpC,YACmB,KAAK,EAAE,MAAM,EAC9B,OAAO,GAAE,SAAoD,EAC5C,OAAO,GAAE,MAAY,EACtC,SAAS,CAAC,EAAE,uBAAuB;IACnC;yEACqE;IACpD,KAAK,CAAC,EAAE,WAAW,YAAA,EAGrC;IAEK,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAuBpD;IAED;;;;;;;;OAQG;IACG,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBnF;CACF;AAmFD,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,aAAa,CAAC,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAC9C,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACtF;AAkBD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,cAAc,CA2KzE;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,QAAQ,CAAC,SAAS,CAAC,EAAE,uBAAuB,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,6BAA6B,CACjD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,8BAA8B,CAAC,CAczC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,GAAG,gBAAgB,CAQzG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,SAAyD,EAClE,MAAM,SAA8C,GACnD,IAAI,CAaN"}