@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.
- package/dist/authors.d.ts +31 -0
- package/dist/authors.js +49 -19
- package/dist/authors.js.map +1 -1
- package/dist/backup.d.ts +5 -3
- package/dist/backup.js +11 -3
- package/dist/backup.js.map +1 -1
- package/dist/client.d.ts +149 -0
- package/dist/client.js +351 -21
- package/dist/client.js.map +1 -1
- package/dist/forwarding/tunnelClient.js +9 -0
- package/dist/forwarding/tunnelClient.js.map +1 -1
- package/dist/identity.d.ts +27 -0
- package/dist/identity.js +36 -0
- package/dist/identity.js.map +1 -1
- package/dist/import.d.ts +265 -0
- package/dist/import.js +313 -0
- package/dist/import.js.map +1 -0
- package/dist/importAssets.d.ts +167 -0
- package/dist/importAssets.js +332 -0
- package/dist/importAssets.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/markdownImport.d.ts +79 -0
- package/dist/markdownImport.js +348 -0
- package/dist/markdownImport.js.map +1 -0
- package/dist/notionImport.d.ts +58 -0
- package/dist/notionImport.js +539 -0
- package/dist/notionImport.js.map +1 -0
- package/dist/routes.d.ts +47 -0
- package/dist/routes.js +48 -0
- package/dist/routes.js.map +1 -1
- package/package.json +11 -5
|
@@ -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":"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"}
|
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`. */
|