@book.dev/sdk 1.65.1 → 1.67.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.
@@ -0,0 +1,539 @@
1
+ /**
2
+ * **Notion "Markdown & CSV" export → import IR.** Ingests the zip Notion produces
3
+ * for *Export → Markdown & CSV* and emits the format-agnostic {@link ImportedDoc}
4
+ * (see `import.ts`), so {@link importDoc} can land the whole tree through the
5
+ * existing data paths (Strategy B — a bundle the server id-remaps, link-rewrites,
6
+ * and name-dedups as one graph).
7
+ *
8
+ * **Export shape.** Notion writes a forest of folders + files; every page/database
9
+ * filename is suffixed with the 32-hex Notion id (dashes stripped):
10
+ *
11
+ * ```
12
+ * Export-<uuid>/ ← transparent wrapper (any non-page dir)
13
+ * Launch Plan <id>.md ← a page
14
+ * Launch Plan <id>/ ← its child pages live here
15
+ * Sub Note <id>.md
16
+ * Team Tasks <id>.csv ← a database (schema + rows)
17
+ * Team Tasks <id>/ ← the database's row pages (bodies)
18
+ * Ship v1 <id>.md
19
+ * ```
20
+ *
21
+ * - **Folder nesting → the page tree.** A `.md` at `A/B/C.md` whose sibling
22
+ * folder `A/B/C/` holds more `.md`/`.csv` becomes an {@link ImportedPage} with
23
+ * those as `children`. Titles drop the hash suffix.
24
+ * - **Each `.md` → blocks** via the merged Markdown importer
25
+ * ({@link markdownToImportedDoc}, T2) — reused verbatim, not reparsed.
26
+ * - **A `.csv` → an {@link ImportedDatabase}.** Column property types are inferred
27
+ * from the cell values (text / number / checkbox / date / select / multi_select
28
+ * / url / email — a comma-bearing cell ⇒ multi_select); each row links to its
29
+ * `.md` page in the sibling folder for the row body. **Scalar properties only**
30
+ * — a CSV cannot encode relation/rollup/formula targets, so those degrade to a
31
+ * plain scalar (never a dangling `relation`), the v1 owner decision.
32
+ * - **Internal links** (the hash-suffixed relative `.md`/`.csv` path Notion
33
+ * writes) resolve to an `@`-mention run when the target was imported; an
34
+ * unresolved internal link keeps its visible text (never dropped). External
35
+ * `http(s)`/`mailto:` links and file/asset refs are preserved as links.
36
+ * - **Icon** — a leading emoji on the page title is lifted to `sys_icon`.
37
+ * - **Images/files** — handled by the Markdown importer as the import core's
38
+ * {@link imagePlaceholderBlock} / a link run that preserves the ref.
39
+ * - **Toggles** — Notion flattens these to a heading/list in Markdown; the
40
+ * content survives via T2 (we do not reconstruct an `accordion`, whose
41
+ * structure does not survive the export).
42
+ *
43
+ * **Never silently drop.** Unknown constructs degrade to text (T2's contract);
44
+ * any `.md`/`.csv` the tree walk somehow misses is appended as a top-level page;
45
+ * a row with no matching body still lands with its properties.
46
+ */
47
+ import { unzipSync, strFromU8 } from 'fflate';
48
+ import { markdownToImportedDoc } from './markdownImport';
49
+ import { IMAGE_PLACEHOLDER_PROP, } from './import';
50
+ import { SELECT_COLORS, shortId, } from './database';
51
+ // ── Path helpers ─────────────────────────────────────────────────────────────
52
+ const baseName = (p) => {
53
+ const i = p.lastIndexOf('/');
54
+ return i < 0 ? p : p.slice(i + 1);
55
+ };
56
+ const dirOf = (p) => {
57
+ const i = p.lastIndexOf('/');
58
+ return i < 0 ? '' : p.slice(0, i);
59
+ };
60
+ /** Strip a trailing `.md` / `.csv` extension. */
61
+ const stripExt = (p) => p.replace(/\.(md|csv)$/i, '');
62
+ /** The 32-hex Notion id embedded in a file's name, if any (the last such run). */
63
+ const NOTION_ID_G = /[0-9a-f]{32}/gi;
64
+ const idOf = (p) => {
65
+ const m = stripExt(baseName(p)).match(NOTION_ID_G);
66
+ return m ? m[m.length - 1].toLowerCase() : null;
67
+ };
68
+ /** A bundle id pinned from a Notion id, so a mention and its target agree. */
69
+ const syntheticId = (notionId) => `imp_n_${notionId}`;
70
+ /** A human title: the basename minus its extension, a trailing `_all` view
71
+ * marker (a database exported as its complete view; see {@link dbKeyOf}), and a
72
+ * trailing ` <32hex>` Notion id. Stripping `_all` keeps the database name clean
73
+ * ("Reading List", not "Reading List <id>_all") when the `_all` view is chosen. */
74
+ const titleOf = (p) => {
75
+ const stem = stripExt(baseName(p)).replace(/_all$/i, '');
76
+ return stem.replace(/\s+[0-9a-f]{32}$/i, '').trim() || stem;
77
+ };
78
+ /** Junk the OS / Notion leaves in a zip that is not page content. */
79
+ const isJunk = (p) => p.startsWith('__MACOSX/') || baseName(p) === '.DS_Store' || baseName(p).startsWith('._');
80
+ // ── Leading-emoji icon ───────────────────────────────────────────────────────
81
+ // A leading emoji (with any variation-selector / ZWJ-joined parts) then whitespace.
82
+ const ICON_RE = /^(\p{Extended_Pictographic}(?:\uFE0F|\u200D\p{Extended_Pictographic})*)\s+([\s\S]+)$/u;
83
+ /** Split a leading emoji off a title → `{icon, title}` (icon undefined if none). */
84
+ function splitIcon(title) {
85
+ const m = ICON_RE.exec(title);
86
+ if (!m)
87
+ return { title };
88
+ return { icon: m[1], title: m[2].trim() };
89
+ }
90
+ // ── CSV parsing ──────────────────────────────────────────────────────────────
91
+ /**
92
+ * RFC-4180-ish CSV → a matrix of rows. Handles quoted fields containing commas
93
+ * and newlines, doubled `""` escapes, and CRLF — everything Notion emits.
94
+ */
95
+ export function parseCsv(text) {
96
+ const rows = [];
97
+ let row = [];
98
+ let field = '';
99
+ let quoted = false;
100
+ let i = text.charCodeAt(0) === 0xfeff ? 1 : 0; // skip a BOM
101
+ const n = text.length;
102
+ while (i < n) {
103
+ const ch = text[i];
104
+ if (quoted) {
105
+ if (ch === '"') {
106
+ if (text[i + 1] === '"') {
107
+ field += '"';
108
+ i += 2;
109
+ continue;
110
+ }
111
+ quoted = false;
112
+ i += 1;
113
+ continue;
114
+ }
115
+ field += ch;
116
+ i += 1;
117
+ continue;
118
+ }
119
+ if (ch === '"') {
120
+ quoted = true;
121
+ i += 1;
122
+ }
123
+ else if (ch === ',') {
124
+ row.push(field);
125
+ field = '';
126
+ i += 1;
127
+ }
128
+ else if (ch === '\n') {
129
+ row.push(field);
130
+ rows.push(row);
131
+ row = [];
132
+ field = '';
133
+ i += 1;
134
+ }
135
+ else if (ch === '\r') {
136
+ i += 1;
137
+ }
138
+ else {
139
+ field += ch;
140
+ i += 1;
141
+ }
142
+ }
143
+ if (field !== '' || row.length > 0) {
144
+ row.push(field);
145
+ rows.push(row);
146
+ }
147
+ return rows;
148
+ }
149
+ // ── Column type inference ────────────────────────────────────────────────────
150
+ const isBoolish = (v) => /^(yes|no|true|false)$/i.test(v);
151
+ const isNumeric = (v) => /^[+-]?(\d+(\.\d+)?|\.\d+)$/.test(v);
152
+ const isUrl = (v) => /^https?:\/\//i.test(v);
153
+ const isEmail = (v) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
154
+ const isDateish = (v) => /^\d{4}-\d{2}-\d{2}([ T]\d{2}:\d{2})?$/.test(v) || /^[A-Za-z]{3,9}\.?\s+\d{1,2},\s+\d{4}/.test(v);
155
+ const all = (xs, pred) => xs.length > 0 && xs.every(pred);
156
+ /** Infer a scalar property type from a column's non-empty cell values. */
157
+ function inferType(values) {
158
+ if (values.length === 0)
159
+ return 'text';
160
+ if (all(values, isBoolish))
161
+ return 'checkbox';
162
+ if (all(values, isNumeric))
163
+ return 'number';
164
+ if (all(values, isDateish))
165
+ return 'date';
166
+ if (all(values, isUrl))
167
+ return 'url';
168
+ if (all(values, isEmail))
169
+ return 'email';
170
+ // A comma-bearing cell is a multi-value list → multi_select.
171
+ if (values.some((v) => v.includes(',')))
172
+ return 'multi_select';
173
+ // Low-cardinality with repeats reads as a single-select; all-distinct is freeform.
174
+ const distinct = new Set(values);
175
+ if (distinct.size < values.length && distinct.size <= 25)
176
+ return 'select';
177
+ return 'text';
178
+ }
179
+ const splitMulti = (v) => v
180
+ .split(',')
181
+ .map((s) => s.trim())
182
+ .filter((s) => s !== '');
183
+ /** Build {@link DatabaseSelectOption}s for a select/multi_select column. */
184
+ function buildOptions(labels) {
185
+ return labels.map((label, i) => ({ id: shortId('opt'), label, color: SELECT_COLORS[i % SELECT_COLORS.length] }));
186
+ }
187
+ /** A normalised `YYYY-MM-DD` for a date cell, or the raw text if unparseable. */
188
+ function toIsoDate(raw) {
189
+ const iso = /^(\d{4}-\d{2}-\d{2})/.exec(raw);
190
+ if (iso)
191
+ return iso[1];
192
+ const d = new Date(raw);
193
+ return Number.isNaN(d.getTime()) ? raw : d.toISOString().slice(0, 10);
194
+ }
195
+ function buildColumn(name, values) {
196
+ const nonEmpty = values.filter((v) => v !== '');
197
+ const type = inferType(nonEmpty);
198
+ const property = { id: shortId('prop'), name: name || 'Untitled', type };
199
+ const optionByLabel = new Map();
200
+ if (type === 'select' || type === 'multi_select') {
201
+ const labels = type === 'multi_select'
202
+ ? [...new Set(nonEmpty.flatMap(splitMulti))]
203
+ : [...new Set(nonEmpty.map((v) => v.trim()))];
204
+ property.options = buildOptions(labels);
205
+ for (const o of property.options)
206
+ optionByLabel.set(o.label, o.id);
207
+ }
208
+ return { property, optionByLabel };
209
+ }
210
+ /** Coerce a raw cell string into the stored value for its column's type. */
211
+ function coerceCell(raw, col) {
212
+ const v = raw.trim();
213
+ if (v === '')
214
+ return undefined;
215
+ switch (col.property.type) {
216
+ case 'number':
217
+ return Number(v);
218
+ case 'checkbox':
219
+ return /^(yes|true)$/i.test(v);
220
+ case 'date':
221
+ return toIsoDate(v);
222
+ case 'select':
223
+ return col.optionByLabel.get(v);
224
+ case 'multi_select':
225
+ return splitMulti(v)
226
+ .map((label) => col.optionByLabel.get(label))
227
+ .filter((id) => typeof id === 'string');
228
+ default:
229
+ return v; // text / url / email
230
+ }
231
+ }
232
+ // ── Internal-link resolution ─────────────────────────────────────────────────
233
+ /** A relative href has no URI scheme and is not an in-page anchor. */
234
+ const isRelative = (href) => !/^[a-z][a-z0-9+.-]*:/i.test(href) && !href.startsWith('#');
235
+ const safeDecode = (s) => {
236
+ try {
237
+ return decodeURIComponent(s);
238
+ }
239
+ catch {
240
+ return s;
241
+ }
242
+ };
243
+ /**
244
+ * Resolve a single href against the imported id set. `change:false` leaves the
245
+ * run as-is (external URL or file/asset ref — the link, and its ref, are kept).
246
+ * `change:true` rewrites it: to an `@`-mention when the target was imported, or
247
+ * to plain text (dropping a dead internal href) when it was not. `attrs` is the
248
+ * run's existing formatting (bold/italic/…), which is preserved either way.
249
+ */
250
+ function resolveHref(attrs, href, knownIds, titleById) {
251
+ if (!isRelative(href))
252
+ return { change: false }; // external URL — leave as-is
253
+ const path = safeDecode(href).split('#')[0].split('?')[0];
254
+ const pointsAtPage = /\.(md|csv)$/i.test(path) || /[0-9a-f]{32}$/i.test(path);
255
+ if (!pointsAtPage)
256
+ return { change: false }; // file/asset ref — keep the link, preserve the ref
257
+ const ids = path.match(NOTION_ID_G);
258
+ const id = ids ? ids[ids.length - 1].toLowerCase() : null;
259
+ const rest = { ...attrs };
260
+ delete rest.a;
261
+ if (id && knownIds.has(id)) {
262
+ return { change: true, attrs: { ...rest, m: syntheticId(id) }, text: titleById.get(id) };
263
+ }
264
+ // Internal, but the target was not imported: keep the visible text, drop the
265
+ // dead relative href (never a click-to-nowhere link).
266
+ return { change: true, attrs: Object.keys(rest).length > 0 ? rest : undefined };
267
+ }
268
+ /** Rewrite link runs across a run list (mentions / preserved links). */
269
+ function resolveRuns(runs, knownIds, titleById) {
270
+ return runs.map((run) => {
271
+ const href = run.a?.a;
272
+ if (!href)
273
+ return run;
274
+ const { change, attrs, text } = resolveHref(run.a, href, knownIds, titleById);
275
+ if (!change)
276
+ return run; // external URL / asset ref — keep the link + ref
277
+ const t = run.t !== '' ? run.t : text ?? run.t;
278
+ return attrs ? { t, a: attrs } : { t };
279
+ });
280
+ }
281
+ /** Resolve links throughout a block tree (skipping synthetic image placeholders). */
282
+ function resolveLinks(blocks, knownIds, titleById) {
283
+ return blocks.map((b) => {
284
+ if (b.props?.[IMAGE_PLACEHOLDER_PROP])
285
+ return b; // the placeholder's link is a real ref, not a page link
286
+ const next = { ...b };
287
+ if (b.text)
288
+ next.text = resolveRuns(b.text, knownIds, titleById);
289
+ if (b.children)
290
+ next.children = resolveLinks(b.children, knownIds, titleById);
291
+ return next;
292
+ });
293
+ }
294
+ /** Resolve `rel` against directory `dir`, collapsing `.`/`..` (a tiny posix-join). */
295
+ function joinPath(dir, rel) {
296
+ const out = [];
297
+ for (const part of (dir ? dir.split('/') : []).concat(rel.split('/'))) {
298
+ if (part === '' || part === '.')
299
+ continue;
300
+ if (part === '..')
301
+ out.pop();
302
+ else
303
+ out.push(part);
304
+ }
305
+ return out.join('/');
306
+ }
307
+ /**
308
+ * Rewrite each image placeholder's `ref` from the Markdown importer's relative
309
+ * `src` (e.g. `Page%20abc/image.png`) to the **absolute in-zip path** of the
310
+ * bytes (`Export-x/Page abc/image.png`), resolved against the source `.md`'s
311
+ * directory — but only when that entry actually exists in the zip. This lets the
312
+ * post-import rehydration pass ({@link notionAssetResolver}) find each image's
313
+ * bytes by a plain `entries[ref]` lookup. An external URL, or a relative ref that
314
+ * matches no entry, is left untouched (it degrades to a placeholder, ref intact).
315
+ */
316
+ function resolveImageRefs(blocks, baseDir, hasEntry) {
317
+ for (const b of blocks) {
318
+ const meta = b.props?.[IMAGE_PLACEHOLDER_PROP];
319
+ if (meta?.ref && isRelative(meta.ref)) {
320
+ const decoded = safeDecode(meta.ref).split('#')[0].split('?')[0];
321
+ const candidate = joinPath(baseDir, decoded);
322
+ if (hasEntry(candidate))
323
+ meta.ref = candidate;
324
+ else if (hasEntry(decoded))
325
+ meta.ref = decoded;
326
+ }
327
+ if (b.children)
328
+ resolveImageRefs(b.children, baseDir, hasEntry);
329
+ }
330
+ }
331
+ /** The row folder a csv's rows live in (a `_all` view shares the plain folder). */
332
+ const dbKeyOf = (csvPath) => stripExt(csvPath).replace(/_all$/i, '');
333
+ /** Direct child `.md` pages of a folder. */
334
+ const childMd = (c, folder) => c.mdPaths.filter((p) => dirOf(p) === folder);
335
+ /** Direct child databases (chosen csvs) of a folder. */
336
+ const childDb = (c, folder) => [...c.csvByKey.values()].filter((p) => dirOf(p) === folder);
337
+ /** Parse a `.md` file → `{icon, title, blocks}` with links resolved. */
338
+ function readPage(c, mdPath) {
339
+ c.consumed.add(mdPath);
340
+ const doc = markdownToImportedDoc(c.text(mdPath), { defaultTitle: titleOf(mdPath) });
341
+ const page = doc.pages[0];
342
+ const { icon, title } = splitIcon(page.title);
343
+ const blocks = resolveLinks(page.blocks, c.knownIds, c.titleById);
344
+ // Point each embedded image at its absolute in-zip path (relative to this .md),
345
+ // so its bytes can be rehydrated into the asset store after import.
346
+ resolveImageRefs(blocks, dirOf(mdPath), c.hasEntry);
347
+ return { icon, title, blocks };
348
+ }
349
+ /** A database row's body: its own blocks plus any sub-pages/sub-dbs flattened in
350
+ * (so a row's nested content is never dropped, even though the row IR has no
351
+ * child-page slot). */
352
+ function rowBody(c, mdPath) {
353
+ const blocks = readPage(c, mdPath).blocks;
354
+ const folder = stripExt(mdPath);
355
+ for (const sub of childMd(c, folder)) {
356
+ const page = readPage(c, sub);
357
+ blocks.push({ type: 'divider' });
358
+ blocks.push({ type: 'heading', props: { level: 3 }, text: [{ t: page.title }] });
359
+ blocks.push(...page.blocks);
360
+ }
361
+ for (const csv of childDb(c, folder)) {
362
+ c.consumed.add(csv);
363
+ const { name, rows } = readDatabase(c, csv);
364
+ blocks.push({ type: 'heading', props: { level: 3 }, text: [{ t: name }] });
365
+ for (const r of rows)
366
+ blocks.push({ type: 'list', props: { kind: 'bullet' }, text: [{ t: r.title }] });
367
+ }
368
+ return blocks;
369
+ }
370
+ /** Parse a csv (+ its row folder) into a name, schema, and rows. */
371
+ function readDatabase(c, csvPath) {
372
+ const name = titleOf(csvPath);
373
+ const matrix = parseCsv(c.text(csvPath));
374
+ const header = matrix[0] ?? [];
375
+ const dataRows = matrix.slice(1).filter((r) => r.some((cell) => cell.trim() !== ''));
376
+ // Columns: the first column is the row title; the rest become properties.
377
+ const columns = [];
378
+ for (let j = 1; j < header.length; j += 1) {
379
+ columns.push(buildColumn(header[j], dataRows.map((r) => r[j] ?? '')));
380
+ }
381
+ const properties = columns.map((col) => col.property);
382
+ const schema = {
383
+ properties,
384
+ views: [{ id: shortId('view'), name: 'Table', type: 'table', filters: [], sorts: [] }],
385
+ };
386
+ // Row bodies: the `.md` pages directly in the database's folder, matched by title.
387
+ const folder = dbKeyOf(csvPath);
388
+ const bodyByTitle = new Map();
389
+ for (const md of childMd(c, folder)) {
390
+ const key = titleOf(md).toLowerCase();
391
+ const list = bodyByTitle.get(key);
392
+ if (list)
393
+ list.push(md);
394
+ else
395
+ bodyByTitle.set(key, [md]);
396
+ }
397
+ const used = new Set();
398
+ const takeBody = (title) => {
399
+ const candidates = bodyByTitle.get(title.trim().toLowerCase());
400
+ const md = candidates?.find((p) => !used.has(p));
401
+ if (md)
402
+ used.add(md);
403
+ return md;
404
+ };
405
+ const rows = dataRows.map((r) => {
406
+ const title = (r[0] ?? '').trim();
407
+ const props = {};
408
+ columns.forEach((col, k) => {
409
+ const value = coerceCell(r[k + 1] ?? '', col);
410
+ if (value !== undefined && !(Array.isArray(value) && value.length === 0))
411
+ props[col.property.id] = value;
412
+ });
413
+ const md = takeBody(title);
414
+ const row = { title, properties: props, blocks: md ? rowBody(c, md) : [] };
415
+ const nid = md ? idOf(md) : null;
416
+ if (nid)
417
+ row.id = syntheticId(nid);
418
+ return row;
419
+ });
420
+ // Any row page with no CSV counterpart still lands (never dropped).
421
+ for (const md of childMd(c, folder)) {
422
+ if (used.has(md))
423
+ continue;
424
+ used.add(md);
425
+ const row = { title: titleOf(md), properties: {}, blocks: rowBody(c, md) };
426
+ const nid = idOf(md);
427
+ if (nid)
428
+ row.id = syntheticId(nid);
429
+ rows.push(row);
430
+ }
431
+ return { name, schema, rows };
432
+ }
433
+ /** Build a regular page node (recursing its child pages and databases). */
434
+ function buildPage(c, mdPath) {
435
+ const { icon, title, blocks } = readPage(c, mdPath);
436
+ const folder = stripExt(mdPath);
437
+ const children = [
438
+ ...childMd(c, folder).map((p) => buildPage(c, p)),
439
+ ...childDb(c, folder).map((p) => buildDatabasePage(c, p)),
440
+ ];
441
+ const page = { title, blocks };
442
+ const nid = idOf(mdPath);
443
+ if (nid)
444
+ page.id = syntheticId(nid);
445
+ if (icon)
446
+ page.icon = icon;
447
+ if (children.length > 0)
448
+ page.children = children;
449
+ return page;
450
+ }
451
+ /** Build the host page that carries a database. */
452
+ function buildDatabasePage(c, csvPath) {
453
+ c.consumed.add(csvPath);
454
+ const { name, schema, rows } = readDatabase(c, csvPath);
455
+ const database = { name, schema, rows };
456
+ const page = { title: name, blocks: [], database };
457
+ const nid = idOf(csvPath);
458
+ if (nid)
459
+ page.id = syntheticId(nid);
460
+ return page;
461
+ }
462
+ // ── Entry point ──────────────────────────────────────────────────────────────
463
+ /**
464
+ * Parse a Notion *Markdown & CSV* export zip into an {@link ImportedDoc} ready for
465
+ * {@link importDoc}. Pure (no client, no I/O beyond the in-memory unzip), so it is
466
+ * directly unit-testable. Throws only when the bytes are not a readable zip.
467
+ */
468
+ export function notionExportToImportedDoc(zipBytes) {
469
+ let entries;
470
+ try {
471
+ entries = unzipSync(zipBytes);
472
+ }
473
+ catch {
474
+ throw new Error('not a readable Notion export zip');
475
+ }
476
+ const paths = Object.keys(entries).filter((p) => !p.endsWith('/') && !isJunk(p));
477
+ const text = (path) => strFromU8(entries[path]);
478
+ const mdPaths = paths.filter((p) => /\.md$/i.test(p));
479
+ const csvPaths = paths.filter((p) => /\.csv$/i.test(p));
480
+ // One database per row folder; prefer a `_all` view (it carries every column).
481
+ const csvByKey = new Map();
482
+ for (const csv of csvPaths) {
483
+ const key = dbKeyOf(csv);
484
+ const current = csvByKey.get(key);
485
+ if (!current || /_all$/i.test(stripExt(csv)))
486
+ csvByKey.set(key, csv);
487
+ }
488
+ const pageFolders = new Set(mdPaths.map(stripExt));
489
+ const dbFolders = new Set(csvByKey.keys());
490
+ // A page/db is a "row descendant" (flattened into its row, not a standalone
491
+ // node) when it lives *below* a database's row folder rather than directly in
492
+ // it. Only standalone nodes are mention targets.
493
+ const isRowDescendant = (p) => [...dbFolders].some((d) => p.startsWith(`${d}/`) && dirOf(p) !== d);
494
+ const knownIds = new Set();
495
+ const titleById = new Map();
496
+ const addNode = (p) => {
497
+ const id = idOf(p);
498
+ if (!id)
499
+ return;
500
+ titleById.set(id, titleOf(p));
501
+ if (!isRowDescendant(p))
502
+ knownIds.add(id);
503
+ };
504
+ mdPaths.forEach(addNode);
505
+ for (const csv of csvByKey.values())
506
+ addNode(csv);
507
+ const consumed = new Set();
508
+ const hasEntry = (p) => Object.prototype.hasOwnProperty.call(entries, p);
509
+ const corpus = { text, mdPaths, csvByKey, knownIds, titleById, consumed, hasEntry };
510
+ // Roots: pages/dbs whose parent dir is neither a page folder nor a database
511
+ // folder — i.e. top-level items (a wrapper like `Export-<uuid>/` is transparent).
512
+ const isRoot = (p) => !pageFolders.has(dirOf(p)) && !dbFolders.has(dirOf(p));
513
+ const pages = [];
514
+ for (const md of mdPaths)
515
+ if (isRoot(md))
516
+ pages.push(buildPage(corpus, md));
517
+ for (const csv of csvByKey.values())
518
+ if (isRoot(csv))
519
+ pages.push(buildDatabasePage(corpus, csv));
520
+ // Safety net: never silently drop a page/db the walk somehow missed.
521
+ for (const md of mdPaths) {
522
+ if (consumed.has(md))
523
+ continue;
524
+ const { icon, title, blocks } = readPage(corpus, md);
525
+ const page = { title, blocks };
526
+ const nid = idOf(md);
527
+ if (nid)
528
+ page.id = syntheticId(nid);
529
+ if (icon)
530
+ page.icon = icon;
531
+ pages.push(page);
532
+ }
533
+ for (const csv of csvByKey.values()) {
534
+ if (!consumed.has(csv))
535
+ pages.push(buildDatabasePage(corpus, csv));
536
+ }
537
+ return { pages };
538
+ }
539
+ //# sourceMappingURL=notionImport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notionImport.js","sourceRoot":"","sources":["../src/notionImport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAC,SAAS,EAAE,SAAS,EAAC,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AACvD,OAAO,EACL,sBAAsB,GAQvB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,OAAO,GAKR,MAAM,YAAY,CAAC;AAEpB,gFAAgF;AAEhF,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE;IACrC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE;IAClC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACpC,CAAC,CAAC;AAEF,iDAAiD;AACjD,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AAEtE,kFAAkF;AAClF,MAAM,WAAW,GAAG,gBAAgB,CAAC;AACrC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAiB,EAAE;IACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACnD,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC,CAAC;AAEF,8EAA8E;AAC9E,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,SAAS,QAAQ,EAAE,CAAC;AAEtE;;;oFAGoF;AACpF,MAAM,OAAO,GAAG,CAAC,CAAS,EAAU,EAAE;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;AAC9D,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,GAAG,CAAC,CAAS,EAAW,EAAE,CACpC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,WAAW,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAE3F,gFAAgF;AAEhF,oFAAoF;AACpF,MAAM,OAAO,GAAG,uFAAuF,CAAC;AAExG,oFAAoF;AACpF,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC;QAAE,OAAO,EAAC,KAAK,EAAC,CAAC;IACvB,OAAO,EAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAC,CAAC;AAC1C,CAAC;AAED,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,IAAI,GAAG,GAAa,EAAE,CAAC;IACvB,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;IAC5D,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACb,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;gBACf,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBACxB,KAAK,IAAI,GAAG,CAAC;oBACb,CAAC,IAAI,CAAC,CAAC;oBACP,SAAS;gBACX,CAAC;gBACD,MAAM,GAAG,KAAK,CAAC;gBACf,CAAC,IAAI,CAAC,CAAC;gBACP,SAAS;YACX,CAAC;YACD,KAAK,IAAI,EAAE,CAAC;YACZ,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,GAAG,IAAI,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,KAAK,GAAG,EAAE,CAAC;YACX,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACvB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,GAAG,GAAG,EAAE,CAAC;YACT,KAAK,GAAG,EAAE,CAAC;YACX,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACvB,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;aAAM,CAAC;YACN,KAAK,IAAI,EAAE,CAAC;YACZ,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;IACH,CAAC;IACD,IAAI,KAAK,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAEhF,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3E,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/E,MAAM,KAAK,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9D,MAAM,OAAO,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7E,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE,CACvC,uCAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,sCAAsC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEpG,MAAM,GAAG,GAAG,CAAC,EAAY,EAAE,IAA4B,EAAW,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAErG,0EAA0E;AAC1E,SAAS,SAAS,CAAC,MAAgB;IACjC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;QAAE,OAAO,UAAU,CAAC;IAC9C,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC5C,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1C,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,6DAA6D;IAC7D,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,cAAc,CAAC;IAC/D,mFAAmF;IACnF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,IAAI,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC1E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,CAAS,EAAY,EAAE,CACzC,CAAC;KACE,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;AAE7B,4EAA4E;AAC5E,SAAS,YAAY,CAAC,MAAgB;IACpC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,EAAC,CAAC,CAAC,CAAC;AACjH,CAAC;AAED,iFAAiF;AACjF,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAQD,SAAS,WAAW,CAAC,IAAY,EAAE,MAAgB;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAqB,EAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,UAAU,EAAE,IAAI,EAAC,CAAC;IACzF,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;QACjD,MAAM,MAAM,GACV,IAAI,KAAK,cAAc;YACrB,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;YAC5C,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAClD,QAAQ,CAAC,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO;YAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,EAAC,QAAQ,EAAE,aAAa,EAAC,CAAC;AACnC,CAAC;AAED,4EAA4E;AAC5E,SAAS,UAAU,CAAC,GAAW,EAAE,GAAW;IAC1C,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC/B,QAAQ,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC5B,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,KAAK,UAAU;YACb,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,KAAK,MAAM;YACT,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;QACtB,KAAK,QAAQ;YACX,OAAO,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,KAAK,cAAc;YACjB,OAAO,UAAU,CAAC,CAAC,CAAC;iBACjB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;iBAC5C,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC;QAC1D;YACE,OAAO,CAAC,CAAC,CAAC,qBAAqB;IACjC,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF,sEAAsE;AACtE,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAE1G,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE;IACvC,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,WAAW,CAClB,KAAwB,EACxB,IAAY,EACZ,QAAqB,EACrB,SAA8B;IAE9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,CAAC,CAAC,6BAA6B;IAC5E,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9E,IAAI,CAAC,YAAY;QAAE,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,CAAC,CAAC,mDAAmD;IAC9F,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1D,MAAM,IAAI,GAAG,EAAC,GAAG,KAAK,EAAC,CAAC;IACxB,OAAO,IAAI,CAAC,CAAC,CAAC;IACd,IAAI,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAC,GAAG,IAAI,EAAE,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,EAAC,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAC,CAAC;IACvF,CAAC;IACD,6EAA6E;IAC7E,sDAAsD;IACtD,OAAO,EAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAC,CAAC;AAChF,CAAC;AAED,wEAAwE;AACxE,SAAS,WAAW,CAAC,IAAqB,EAAE,QAAqB,EAAE,SAA8B;IAC/F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACtB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI;YAAE,OAAO,GAAG,CAAC;QACtB,MAAM,EAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC7E,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,CAAC,CAAC,iDAAiD;QAC1E,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,CAAC,CAAC,EAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAC,CAAC,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,qFAAqF;AACrF,SAAS,YAAY,CAAC,MAAuB,EAAE,QAAqB,EAAE,SAA8B;IAClG,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACtB,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,sBAAsB,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,wDAAwD;QACzG,MAAM,IAAI,GAAkB,EAAC,GAAG,CAAC,EAAC,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,QAAQ;YAAE,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAiBD,sFAAsF;AACtF,SAAS,QAAQ,CAAC,GAAW,EAAE,GAAW;IACxC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACtE,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,GAAG;YAAE,SAAS;QAC1C,IAAI,IAAI,KAAK,IAAI;YAAE,GAAG,CAAC,GAAG,EAAE,CAAC;;YACxB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CAAC,MAAuB,EAAE,OAAe,EAAE,QAAgC;IAClG,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,sBAAsB,CAA+B,CAAC;QAC7E,IAAI,IAAI,EAAE,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,IAAI,QAAQ,CAAC,SAAS,CAAC;gBAAE,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;iBACzC,IAAI,QAAQ,CAAC,OAAO,CAAC;gBAAE,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,CAAC,QAAQ;YAAE,gBAAgB,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,OAAO,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAErF,4CAA4C;AAC5C,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,MAAc,EAAY,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;AAEtG,wDAAwD;AACxD,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,MAAc,EAAY,EAAE,CACtD,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;AAE9D,wEAAwE;AACxE,SAAS,QAAQ,CAAC,CAAS,EAAE,MAAc;IACzC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,GAAG,GAAG,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,EAAC,CAAC,CAAC;IACnF,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,EAAC,IAAI,EAAE,KAAK,EAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;IAClE,gFAAgF;IAChF,oEAAoE;IACpE,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACpD,OAAO,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAC,CAAC;AAC/B,CAAC;AAED;;wBAEwB;AACxB,SAAS,OAAO,CAAC,CAAS,EAAE,MAAc;IACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAC,KAAK,EAAE,CAAC,EAAC,EAAE,IAAI,EAAE,CAAC,EAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAC,CAAC,EAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;QACrC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpB,MAAM,EAAC,IAAI,EAAE,IAAI,EAAC,GAAG,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAC,KAAK,EAAE,CAAC,EAAC,EAAE,IAAI,EAAE,CAAC,EAAC,CAAC,EAAE,IAAI,EAAC,CAAC,EAAC,CAAC,CAAC;QACrE,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAE,IAAI,EAAE,CAAC,EAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAC,CAAC,EAAC,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,oEAAoE;AACpE,SAAS,YAAY,CAAC,CAAS,EAAE,OAAe;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAErF,0EAA0E;IAC1E,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,MAAM,GAAmB;QAC7B,UAAU;QACV,KAAK,EAAE,CAAC,EAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAC,CAAC;KACrF,CAAC;IAEF,mFAAmF;IACnF,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAChD,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YACnB,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAsB,EAAE;QACrD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/D,MAAM,EAAE,GAAG,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,EAAE;YAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,MAAM,IAAI,GAAkB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7C,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,KAAK,GAA4B,EAAE,CAAC;QAC1C,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;YAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;QAC3G,CAAC,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3B,MAAM,GAAG,GAAgB,EAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAC,CAAC;QACtF,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACjC,IAAI,GAAG;YAAE,GAAG,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,oEAAoE;IACpE,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,MAAM,GAAG,GAAgB,EAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAC,CAAC;QACtF,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,IAAI,GAAG;YAAE,GAAG,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC,CAAC;AAC9B,CAAC;AAED,2EAA2E;AAC3E,SAAS,SAAS,CAAC,CAAS,EAAE,MAAc;IAC1C,MAAM,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAmB;QAC/B,GAAG,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,GAAG,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAC1D,CAAC;IACF,MAAM,IAAI,GAAiB,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mDAAmD;AACnD,SAAS,iBAAiB,CAAC,CAAS,EAAE,OAAe;IACnD,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC,GAAG,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAqB,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC,CAAC;IACxD,MAAM,IAAI,GAAiB,EAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1B,IAAI,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAoB;IAC5D,IAAI,OAAmC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAExD,+EAA+E;IAC/E,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAE3C,4EAA4E;IAC5E,8EAA8E;IAC9E,iDAAiD;IACjD,MAAM,eAAe,GAAG,CAAC,CAAS,EAAW,EAAE,CAC7C,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAEtE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,CAAS,EAAQ,EAAE;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC;IACF,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAElD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC1F,MAAM,MAAM,GAAW,EAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAC,CAAC;IAE1F,4EAA4E;IAC5E,kFAAkF;IAClF,MAAM,MAAM,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,KAAK,MAAM,EAAE,IAAI,OAAO;QAAE,IAAI,MAAM,CAAC,EAAE,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IAC5E,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,MAAM,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAEjG,qEAAqE;IACrE,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC/B,MAAM,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,IAAI,GAAiB,EAAC,KAAK,EAAE,MAAM,EAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,IAAI,GAAG;YAAE,IAAI,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,EAAC,KAAK,EAAC,CAAC;AACjB,CAAC"}
package/dist/routes.d.ts CHANGED
@@ -29,6 +29,36 @@ export declare const API: {
29
29
  readonly stream: "/api/stream";
30
30
  /** SSE stream of a single page's live updates + deletion. */
31
31
  readonly pageStream: (id: string) => string;
32
+ /**
33
+ * Live collaboration — incremental update ingest (Collab T1). `POST` an opaque
34
+ * base64 Yjs update `{update, clientId}`; the server fans it out to readers as a
35
+ * `yupdate` firehose frame (write-gated in, read-gated out) and folds it into an
36
+ * in-memory relay doc so a late joiner can catch up — but persists NOTHING. The
37
+ * debounced snapshot save (`PUT /api/pages/:id`) remains the sole durable
38
+ * checkpoint, so the relay is a best-effort live nudge, never a system of record.
39
+ */
40
+ readonly pageUpdates: (id: string) => string;
41
+ /**
42
+ * Live collaboration — late-joiner sync handshake (Collab T1). `POST {sv}` (the
43
+ * client's base64 Yjs state vector); the server replies `{update}` with exactly
44
+ * the ops the client is missing, computed from the relay doc (seeded from the
45
+ * durable snapshot + every relayed update since). Read-gated. This is what lets a
46
+ * client that connects mid-session converge to the CURRENT doc, not just future
47
+ * edits.
48
+ */
49
+ readonly pageSync: (id: string) => string;
50
+ /**
51
+ * Live collaboration — ephemeral awareness/presence (Collab T4). `POST` a base64
52
+ * `y-protocols/awareness` update `{update, clientId}` to publish this client's
53
+ * presence (cursor / selection); the server **re-stamps the identity** from the
54
+ * verified principal (so name/colour can't be spoofed via the body) and fans it
55
+ * out to readers as an `awareness` firehose frame. Unlike `/updates` this is
56
+ * **read-gated** — a viewer (read, not write) appears present, the T6 "viewers
57
+ * broadcast presence" behaviour. `GET` returns the current presence snapshot
58
+ * (`{updates: base64[]}`) so a late joiner sees who's here immediately. Persists
59
+ * NOTHING — never in the durable snapshot, never in the edit log.
60
+ */
61
+ readonly pageAwareness: (id: string) => string;
32
62
  /**
33
63
  * The multiplexed live stream: one SSE connection carrying every event (page
34
64
  * list, page updates/deletions, database rows). Clients open exactly one of
@@ -74,6 +104,23 @@ export declare const API: {
74
104
  readonly aiSkill: (name: string) => string;
75
105
  readonly plugins: "/api/plugins";
76
106
  readonly plugin: (id: string) => string;
107
+ /**
108
+ * Upload an asset: `POST /api/assets?pageId=<id>`. The body is the raw binary
109
+ * (its `Content-Type` header is the stored mime), or — for the in-webview
110
+ * transports whose bridge corrupts raw binary — a JSON `{data: base64, mime}`.
111
+ * Write-gated to `pageId` (a page the uploader can write); the asset is ref'd to
112
+ * that page so it's immediately reachable. 10 MiB cap (413 past it). Returns
113
+ * `{id}` — the SHA-256 content hash (byte-identical uploads dedup to one id).
114
+ */
115
+ readonly assets: "/api/assets";
116
+ /**
117
+ * Fetch an asset by its content-hash id. `GET /api/assets/:id` serves the raw
118
+ * binary with the stored `Content-Type`; `?encoding=base64` returns a JSON
119
+ * `{id, mime, size, data: base64}` for the in-webview transports. **Read-gated**:
120
+ * served only to a caller who can read at least one page that references the
121
+ * asset — otherwise 404 (no existence oracle).
122
+ */
123
+ readonly asset: (id: string) => string;
77
124
  /** A page's suggestions: `GET` (list, optionally `?status=open`) / `POST` (create). */
78
125
  readonly suggestions: (pageId: string) => string;
79
126
  /** A single suggestion: `PATCH` (status: accepted/rejected) / `DELETE`. */