@kernhq/module-quire 0.13.0 → 0.14.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 (101) hide show
  1. package/dist/contract/models.d.ts +185 -0
  2. package/dist/contract/models.d.ts.map +1 -1
  3. package/dist/contract/models.js +133 -0
  4. package/dist/contract/models.js.map +1 -1
  5. package/dist/contract/permissions.d.ts +14 -0
  6. package/dist/contract/permissions.d.ts.map +1 -1
  7. package/dist/contract/permissions.js +82 -0
  8. package/dist/contract/permissions.js.map +1 -1
  9. package/dist/contract/properties.d.ts +4 -4
  10. package/dist/contract/router.d.ts +542 -15
  11. package/dist/contract/router.d.ts.map +1 -1
  12. package/dist/contract/router.js +155 -8
  13. package/dist/contract/router.js.map +1 -1
  14. package/dist/server/_impl.d.ts +526 -15
  15. package/dist/server/_impl.d.ts.map +1 -1
  16. package/dist/server/_impl.js +166 -23
  17. package/dist/server/_impl.js.map +1 -1
  18. package/dist/server/export/html.d.ts +67 -0
  19. package/dist/server/export/html.d.ts.map +1 -0
  20. package/dist/server/export/html.js +206 -0
  21. package/dist/server/export/html.js.map +1 -0
  22. package/dist/server/export/markdown.d.ts +51 -0
  23. package/dist/server/export/markdown.d.ts.map +1 -0
  24. package/dist/server/export/markdown.js +312 -0
  25. package/dist/server/export/markdown.js.map +1 -0
  26. package/dist/server/export/pdf.d.ts +20 -0
  27. package/dist/server/export/pdf.d.ts.map +1 -0
  28. package/dist/server/export/pdf.js +91 -0
  29. package/dist/server/export/pdf.js.map +1 -0
  30. package/dist/server/export/zip.d.ts +31 -0
  31. package/dist/server/export/zip.d.ts.map +1 -0
  32. package/dist/server/export/zip.js +158 -0
  33. package/dist/server/export/zip.js.map +1 -0
  34. package/dist/server/import/csv.d.ts +77 -0
  35. package/dist/server/import/csv.d.ts.map +1 -0
  36. package/dist/server/import/csv.js +263 -0
  37. package/dist/server/import/csv.js.map +1 -0
  38. package/dist/server/import/html.d.ts +52 -0
  39. package/dist/server/import/html.d.ts.map +1 -0
  40. package/dist/server/import/html.js +472 -0
  41. package/dist/server/import/html.js.map +1 -0
  42. package/dist/server/import/markdown.d.ts +63 -0
  43. package/dist/server/import/markdown.d.ts.map +1 -0
  44. package/dist/server/import/markdown.js +692 -0
  45. package/dist/server/import/markdown.js.map +1 -0
  46. package/dist/server/import/plan.d.ts +70 -0
  47. package/dist/server/import/plan.d.ts.map +1 -0
  48. package/dist/server/import/plan.js +761 -0
  49. package/dist/server/import/plan.js.map +1 -0
  50. package/dist/server/import/ydoc.d.ts +35 -0
  51. package/dist/server/import/ydoc.d.ts.map +1 -0
  52. package/dist/server/import/ydoc.js +91 -0
  53. package/dist/server/import/ydoc.js.map +1 -0
  54. package/dist/server/import/zip.d.ts +63 -0
  55. package/dist/server/import/zip.d.ts.map +1 -0
  56. package/dist/server/import/zip.js +308 -0
  57. package/dist/server/import/zip.js.map +1 -0
  58. package/dist/server/index.d.ts.map +1 -1
  59. package/dist/server/index.js +3 -1
  60. package/dist/server/index.js.map +1 -1
  61. package/dist/server/schema.d.ts +445 -1
  62. package/dist/server/schema.d.ts.map +1 -1
  63. package/dist/server/schema.js +146 -0
  64. package/dist/server/schema.js.map +1 -1
  65. package/dist/server/services/databases.d.ts +5 -5
  66. package/dist/server/services/export.d.ts +176 -0
  67. package/dist/server/services/export.d.ts.map +1 -0
  68. package/dist/server/services/export.js +822 -0
  69. package/dist/server/services/export.js.map +1 -0
  70. package/dist/server/services/import.d.ts +109 -0
  71. package/dist/server/services/import.d.ts.map +1 -0
  72. package/dist/server/services/import.js +570 -0
  73. package/dist/server/services/import.js.map +1 -0
  74. package/dist/server/services/index.d.ts +28 -1
  75. package/dist/server/services/index.d.ts.map +1 -1
  76. package/dist/server/services/index.js +62 -1
  77. package/dist/server/services/index.js.map +1 -1
  78. package/dist/server/services/publications.d.ts +34 -1
  79. package/dist/server/services/publications.d.ts.map +1 -1
  80. package/dist/server/services/publications.js +62 -3
  81. package/dist/server/services/publications.js.map +1 -1
  82. package/dist/server/services/versions.d.ts +1 -1
  83. package/migrations/0010_transfers.sql +154 -0
  84. package/migrations/meta/_journal.json +7 -0
  85. package/package.json +1 -1
  86. package/src/client/components/ExportDialog.svelte +685 -0
  87. package/src/client/components/ImportDialog.svelte +702 -0
  88. package/src/client/components/ImportReport.svelte +310 -0
  89. package/src/client/components/SidebarSpaces.svelte +79 -0
  90. package/src/client/i18n.ts +614 -0
  91. package/src/client/index.ts +32 -0
  92. package/src/client/mock.ts +318 -0
  93. package/src/client/module.ts +36 -0
  94. package/src/client/pages/PageView.svelte +36 -0
  95. package/src/client/pages/TransfersPage.svelte +570 -0
  96. package/src/client/permissions.ts +11 -0
  97. package/src/client/query.ts +23 -0
  98. package/src/client/transfers.ts +142 -0
  99. package/src/contract/models.ts +152 -0
  100. package/src/contract/permissions.ts +84 -0
  101. package/src/contract/router.ts +170 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/server/export/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /** Where the compose stack puts it. `dev/compose.yml` publishes 3500 on the host. */
2
+ export declare const DEFAULT_GOTENBERG_URL = "http://gotenberg:3000";
3
+ export declare const gotenbergUrl: () => string;
4
+ export interface PdfOptions {
5
+ /** overrides `GOTENBERG_URL`; the export job does not pass one, the test does */
6
+ url?: string;
7
+ timeoutMs?: number;
8
+ /** what Chromium prints in the footer's page numbers, and nothing else */
9
+ title?: string;
10
+ }
11
+ /**
12
+ * A complete PDF, or a throw.
13
+ *
14
+ * The HTML has to be self-contained. Gotenberg's Chromium fetches whatever the document references,
15
+ * from inside its own container — so a presigned storage URL in an `<img src>` is both a network
16
+ * dependency this has no business having and a workspace uuid handed to a process that did not need
17
+ * it. Pictures reach here as `data:` URIs, put there by the caller.
18
+ */
19
+ export declare function htmlToPdf(html: string, options?: PdfOptions): Promise<Buffer>;
20
+ //# sourceMappingURL=pdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../../../src/server/export/pdf.ts"],"names":[],"mappings":"AA2BA,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,0BAA0B,CAAA;AAE5D,eAAO,MAAM,YAAY,QAAO,MAAoE,CAAA;AAQpG,MAAM,WAAW,UAAU;IACzB,iFAAiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DvF"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * HTML to PDF, through Gotenberg.
3
+ *
4
+ * Gotenberg is a Chromium in a container, and it is already in the stack: `selfhost/docker-compose.yml`
5
+ * starts it under `--profile preview`, `dev/compose.yml` publishes it on 3500. Nothing in Kern had
6
+ * ever called it, so this is the first caller and the first thing that has to answer the question
7
+ * every optional dependency raises — **what happens when it is not there.**
8
+ *
9
+ * The answer is one sentence with three parts, and every one of them is load-bearing:
10
+ *
11
+ * - it never produces a half file. The bytes are read in full, in memory, before anything is
12
+ * written anywhere; a refusal, a timeout or a closed port throws before the caller has an
13
+ * artefact to store, so an export job goes to `failed` with `file_id` still null rather than to
14
+ * `done` with a truncated PDF a reader would find out about by opening it;
15
+ * - the failure names the URL it tried and the variable that changes it, because the person who
16
+ * reads it is an operator looking at a stack, not a developer looking at a stack trace. "PDF
17
+ * export could not reach Gotenberg at http://gotenberg:3000" is actionable; `ECONNREFUSED` is
18
+ * not;
19
+ * - it is bounded. Chromium rendering a five-hundred-page handbook can take minutes or can hang,
20
+ * and a job that hangs holds a worker for ever. The request carries a timeout and gives up.
21
+ *
22
+ * The default points at the compose service name rather than at nothing, so an instance that has the
23
+ * `preview` profile on needs no configuration at all and one that does not gets a refusal naming
24
+ * `GOTENBERG_URL`.
25
+ */
26
+ import { KernError } from '@kernhq/kernel';
27
+ /** Where the compose stack puts it. `dev/compose.yml` publishes 3500 on the host. */
28
+ export const DEFAULT_GOTENBERG_URL = 'http://gotenberg:3000';
29
+ export const gotenbergUrl = () => process.env.GOTENBERG_URL?.trim() || DEFAULT_GOTENBERG_URL;
30
+ /** Long enough for a big handbook, short enough that a wedged Chromium is not a wedged worker. */
31
+ const DEFAULT_TIMEOUT_MS = 120_000;
32
+ /** A refusal's body is a diagnostic, not a document: enough to act on, never a page of HTML in a log. */
33
+ const REASON_LIMIT = 400;
34
+ /**
35
+ * A complete PDF, or a throw.
36
+ *
37
+ * The HTML has to be self-contained. Gotenberg's Chromium fetches whatever the document references,
38
+ * from inside its own container — so a presigned storage URL in an `<img src>` is both a network
39
+ * dependency this has no business having and a workspace uuid handed to a process that did not need
40
+ * it. Pictures reach here as `data:` URIs, put there by the caller.
41
+ */
42
+ export async function htmlToPdf(html, options = {}) {
43
+ const base = (options.url ?? gotenbergUrl()).replace(/\/+$/, '');
44
+ const endpoint = `${base}/forms/chromium/convert/html`;
45
+ const form = new FormData();
46
+ // The part *must* be named `index.html`; Gotenberg renders that file and treats the rest as assets.
47
+ form.append('files', new Blob([html], { type: 'text/html' }), 'index.html');
48
+ form.append('paperWidth', '8.27');
49
+ form.append('paperHeight', '11.7');
50
+ form.append('marginTop', '0.6');
51
+ form.append('marginBottom', '0.6');
52
+ form.append('marginLeft', '0.6');
53
+ form.append('marginRight', '0.6');
54
+ form.append('printBackground', 'true');
55
+ // Without this a callout's tint and a code block's ground are dropped and the page loses its shape.
56
+ form.append('preferCssPageSize', 'false');
57
+ if (options.title)
58
+ form.append('metadata', JSON.stringify({ Title: options.title, Creator: 'Kern Quire' }));
59
+ let response;
60
+ try {
61
+ response = await fetch(endpoint, {
62
+ method: 'POST',
63
+ body: form,
64
+ signal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
65
+ });
66
+ }
67
+ catch (err) {
68
+ const why = err instanceof Error && err.name === 'TimeoutError' ? 'did not answer in time' : 'is not reachable';
69
+ throw new KernError('UNAVAILABLE', `PDF export needs Gotenberg, and ${base} ${why}. Start it (the self-host stack has it under ` +
70
+ '`--profile preview`) or point GOTENBERG_URL at one that is running.', { service: 'gotenberg', url: base });
71
+ }
72
+ if (!response.ok) {
73
+ const reason = await response.text().catch(() => '');
74
+ throw new KernError('UNAVAILABLE', `Gotenberg at ${base} refused to render this page (HTTP ${response.status}). ` +
75
+ `${reason.slice(0, REASON_LIMIT) || 'It gave no reason.'}`, { service: 'gotenberg', url: base, status: response.status });
76
+ }
77
+ const bytes = Buffer.from(await response.arrayBuffer());
78
+ /*
79
+ * A zero-length 200 is a real Gotenberg failure mode when Chromium dies mid-render, and it is the
80
+ * one that would otherwise be stored: an empty file, a job marked `done`, and a person who finds
81
+ * out by double-clicking it. `%PDF` is four bytes and settles it.
82
+ */
83
+ if (bytes.length === 0 || bytes.subarray(0, 4).toString('latin1') !== '%PDF')
84
+ throw new KernError('UNAVAILABLE', `Gotenberg at ${base} returned something that is not a PDF`, {
85
+ service: 'gotenberg',
86
+ url: base,
87
+ bytes: bytes.length,
88
+ });
89
+ return bytes;
90
+ }
91
+ //# sourceMappingURL=pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../../src/server/export/pdf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export declare function crc32(data: Uint8Array): number;
2
+ export interface ZipEntry {
3
+ /** the path inside the archive, `/`-separated and never absolute or `..`-relative */
4
+ path: string;
5
+ data: Uint8Array;
6
+ }
7
+ /** What a caller may not exceed, so a refusal can name the number it broke. */
8
+ export declare const ZIP_LIMITS: {
9
+ maxTotalBytes: number;
10
+ maxEntryBytes: number;
11
+ maxEntries: number;
12
+ };
13
+ /**
14
+ * A path that cannot escape the folder somebody unzips into.
15
+ *
16
+ * A page title becomes a folder name, and a title is user input: `../../etc/whatever` is a real
17
+ * archive somebody can be handed, and a tool that follows it writes outside the extraction
18
+ * directory. Every segment is cleaned rather than rejected, because refusing an export because
19
+ * somebody named a page `C:\` would be absurd — but the cleaning is total, so nothing survives that
20
+ * a reader could resolve upwards.
21
+ */
22
+ export declare function safeZipPath(path: string): string;
23
+ /**
24
+ * Every entry, in one buffer.
25
+ *
26
+ * Sizes are known before anything is written, so no entry carries a data descriptor and no reader
27
+ * has to seek backwards — which is what makes the output openable by the strictest tools as well as
28
+ * by the forgiving ones.
29
+ */
30
+ export declare function writeZip(entries: ZipEntry[], now?: Date): Buffer;
31
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../../src/server/export/zip.ts"],"names":[],"mappings":"AAqCA,wBAAgB,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAI9C;AAkBD,MAAM,WAAW,QAAQ;IACvB,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,+EAA+E;AAC/E,eAAO,MAAM,UAAU;;;;CAA4E,CAAA;AAEnG;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAchD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAa,GAAG,MAAM,CA4EtE"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * A zip container, written by hand.
3
+ *
4
+ * An export of a subtree or a space is a folder per page with its pictures beside it, which is a zip
5
+ * and cannot reasonably be anything else. Writing the container here rather than taking a dependency
6
+ * is a deliberate trade and worth stating: the format needed is the 1989 one — deflate or store, no
7
+ * encryption, no ZIP64, sizes known before the entry is written — and that is about a hundred lines
8
+ * of well-specified header. `archiver` and `jszip` are streaming libraries whose job is everything
9
+ * this does not need, and every module repository commits its own lockfile, so a dependency here is
10
+ * a lockfile refresh outside the workspace in six places before it is a line of code.
11
+ *
12
+ * The limits are the honest part of that trade, and they are checked rather than assumed. No ZIP64
13
+ * means an archive is refused above 4 GiB, an entry above 4 GiB, or 65,535 entries — refused with a
14
+ * message, never truncated into a file that unzips to something incomplete. An export that would hit
15
+ * one of those is a job that fails and says so, which is the rule the whole slice is built on.
16
+ *
17
+ * Everything is deflated except what deflate makes bigger, which is most already-compressed pictures.
18
+ * The comparison is done rather than guessed from the extension: a PNG of flat colour still shrinks.
19
+ */
20
+ import { deflateRawSync } from 'node:zlib';
21
+ /** 0xFFFFFFFF. Above this an offset or a size needs ZIP64, which this writer does not emit. */
22
+ const MAX_32 = 0xffff_ffff;
23
+ /** The count field in the end-of-central-directory record is 16 bits. */
24
+ const MAX_ENTRIES = 0xffff;
25
+ /** `crc32` over the whole entry, which the reader checks — a wrong one is a "corrupt archive". */
26
+ const CRC_TABLE = (() => {
27
+ const table = new Int32Array(256);
28
+ for (let n = 0; n < 256; n++) {
29
+ let c = n;
30
+ for (let k = 0; k < 8; k++)
31
+ c = c & 1 ? 0xedb8_8320 ^ (c >>> 1) : c >>> 1;
32
+ table[n] = c;
33
+ }
34
+ return table;
35
+ })();
36
+ export function crc32(data) {
37
+ let c = 0xffff_ffff;
38
+ for (let i = 0; i < data.length; i++)
39
+ c = CRC_TABLE[(c ^ data[i]) & 0xff] ^ (c >>> 8);
40
+ return (c ^ 0xffff_ffff) >>> 0;
41
+ }
42
+ /**
43
+ * The MS-DOS date and time a zip entry carries, from a real clock.
44
+ *
45
+ * Not a constant: an archive whose every file is stamped 1980 looks broken in a file manager, and
46
+ * some restore tools treat it as such. The resolution is two seconds, which is the format's, and the
47
+ * clock is UTC because the format has no zone and a local one would make the same export produce
48
+ * different bytes on two machines.
49
+ */
50
+ function dosStamp(at) {
51
+ const year = Math.max(1980, at.getUTCFullYear());
52
+ return {
53
+ time: (at.getUTCHours() << 11) | (at.getUTCMinutes() << 5) | (at.getUTCSeconds() >> 1),
54
+ date: ((year - 1980) << 9) | ((at.getUTCMonth() + 1) << 5) | at.getUTCDate(),
55
+ };
56
+ }
57
+ /** What a caller may not exceed, so a refusal can name the number it broke. */
58
+ export const ZIP_LIMITS = { maxTotalBytes: MAX_32, maxEntryBytes: MAX_32, maxEntries: MAX_ENTRIES };
59
+ /**
60
+ * A path that cannot escape the folder somebody unzips into.
61
+ *
62
+ * A page title becomes a folder name, and a title is user input: `../../etc/whatever` is a real
63
+ * archive somebody can be handed, and a tool that follows it writes outside the extraction
64
+ * directory. Every segment is cleaned rather than rejected, because refusing an export because
65
+ * somebody named a page `C:\` would be absurd — but the cleaning is total, so nothing survives that
66
+ * a reader could resolve upwards.
67
+ */
68
+ export function safeZipPath(path) {
69
+ const segments = path
70
+ .split('/')
71
+ .map((segment) => segment
72
+ .normalize('NFC')
73
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: control characters are exactly what a filename must not carry
74
+ .replace(/[\u0000-\u001f\u007f\\:*?"<>|]+/g, '-')
75
+ .replace(/^\.+$/, '-')
76
+ .replace(/^\s+|[\s.]+$/g, '')
77
+ .slice(0, 100))
78
+ .filter((segment) => segment.length > 0);
79
+ return segments.join('/');
80
+ }
81
+ /**
82
+ * Every entry, in one buffer.
83
+ *
84
+ * Sizes are known before anything is written, so no entry carries a data descriptor and no reader
85
+ * has to seek backwards — which is what makes the output openable by the strictest tools as well as
86
+ * by the forgiving ones.
87
+ */
88
+ export function writeZip(entries, now = new Date()) {
89
+ if (entries.length > MAX_ENTRIES)
90
+ throw new Error(`This export has ${entries.length} files, and a zip may hold ${MAX_ENTRIES}`);
91
+ const { time, date } = dosStamp(now);
92
+ const locals = [];
93
+ const centrals = [];
94
+ let offset = 0;
95
+ for (const entry of entries) {
96
+ const name = Buffer.from(entry.path, 'utf8');
97
+ const raw = Buffer.from(entry.data.buffer, entry.data.byteOffset, entry.data.byteLength);
98
+ if (raw.length > MAX_32)
99
+ throw new Error(`${entry.path} is larger than 4 GB, which a zip cannot hold`);
100
+ const deflated = raw.length > 0 ? deflateRawSync(raw, { level: 6 }) : Buffer.alloc(0);
101
+ // Stored rather than deflated when deflate did not help — which is the normal case for a JPEG.
102
+ const compress = deflated.length < raw.length;
103
+ const body = compress ? deflated : raw;
104
+ const crc = crc32(raw);
105
+ if (offset > MAX_32 - body.length - name.length - 30)
106
+ throw new Error('This export is larger than 4 GB, which is more than a zip can address');
107
+ const local = Buffer.alloc(30);
108
+ local.writeUInt32LE(0x0403_4b50, 0);
109
+ local.writeUInt16LE(20, 4);
110
+ // 0x0800: the name below is UTF-8. Without it a Persian page title is mojibake on extraction.
111
+ local.writeUInt16LE(0x0800, 6);
112
+ local.writeUInt16LE(compress ? 8 : 0, 8);
113
+ local.writeUInt16LE(time, 10);
114
+ local.writeUInt16LE(date, 12);
115
+ local.writeUInt32LE(crc, 14);
116
+ local.writeUInt32LE(body.length, 18);
117
+ local.writeUInt32LE(raw.length, 22);
118
+ local.writeUInt16LE(name.length, 26);
119
+ local.writeUInt16LE(0, 28);
120
+ locals.push(local, name, body);
121
+ const central = Buffer.alloc(46);
122
+ central.writeUInt32LE(0x0201_4b50, 0);
123
+ // Made by a Unix zip (3), spec 2.0 — so the permission bits below are read as Unix ones.
124
+ central.writeUInt16LE(0x0314, 4);
125
+ central.writeUInt16LE(20, 6);
126
+ central.writeUInt16LE(0x0800, 8);
127
+ central.writeUInt16LE(compress ? 8 : 0, 10);
128
+ central.writeUInt16LE(time, 12);
129
+ central.writeUInt16LE(date, 14);
130
+ central.writeUInt32LE(crc, 16);
131
+ central.writeUInt32LE(body.length, 20);
132
+ central.writeUInt32LE(raw.length, 24);
133
+ central.writeUInt16LE(name.length, 28);
134
+ central.writeUInt16LE(0, 30);
135
+ central.writeUInt16LE(0, 32);
136
+ central.writeUInt16LE(0, 34);
137
+ central.writeUInt16LE(0, 36);
138
+ // 0o100644 in the high half: a regular file somebody owns and everyone may read.
139
+ // Multiplied rather than shifted — `<<` is a 32-bit *signed* operator, so `0o100644 << 16` is
140
+ // negative and `writeUInt32LE` throws on it. The whole archive fails to build, at the last entry.
141
+ central.writeUInt32LE(0o100644 * 0x1_0000, 38);
142
+ central.writeUInt32LE(offset, 42);
143
+ centrals.push(central, name);
144
+ offset += local.length + name.length + body.length;
145
+ }
146
+ const directory = Buffer.concat(centrals);
147
+ const end = Buffer.alloc(22);
148
+ end.writeUInt32LE(0x0605_4b50, 0);
149
+ end.writeUInt16LE(0, 4);
150
+ end.writeUInt16LE(0, 6);
151
+ end.writeUInt16LE(entries.length, 8);
152
+ end.writeUInt16LE(entries.length, 10);
153
+ end.writeUInt32LE(directory.length, 12);
154
+ end.writeUInt32LE(offset, 16);
155
+ end.writeUInt16LE(0, 20);
156
+ return Buffer.concat([...locals, directory, end]);
157
+ }
158
+ //# sourceMappingURL=zip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../../src/server/export/zip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE1C,+FAA+F;AAC/F,MAAM,MAAM,GAAG,WAAW,CAAA;AAC1B,yEAAyE;AACzE,MAAM,WAAW,GAAG,MAAM,CAAA;AAE1B,kGAAkG;AAClG,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE;IACtB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAA;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,CAAA;QACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACzE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IACd,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAC,EAAE,CAAA;AAEJ,MAAM,UAAU,KAAK,CAAC,IAAgB;IACpC,IAAI,CAAC,GAAG,WAAW,CAAA;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC,GAAG,IAAI,CAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IACvF,OAAO,CAAC,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,EAAQ;IACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,EAAE,CAAC,CAAA;IAChD,OAAO;QACL,IAAI,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QACtF,IAAI,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE;KAC7E,CAAA;AACH,CAAC;AAQD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,CAAA;AAEnG;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,QAAQ,GAAG,IAAI;SAClB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACf,OAAO;SACJ,SAAS,CAAC,KAAK,CAAC;QACjB,yHAAyH;SACxH,OAAO,CAAC,kCAAkC,EAAE,GAAG,CAAC;SAChD,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CACjB;SACA,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC1C,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAmB,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IAC5D,IAAI,OAAO,CAAC,MAAM,GAAG,WAAW;QAC9B,MAAM,IAAI,KAAK,CAAC,mBAAmB,OAAO,CAAC,MAAM,8BAA8B,WAAW,EAAE,CAAC,CAAA;IAE/F,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IACpC,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,IAAI,MAAM,GAAG,CAAC,CAAA;IAEd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACxF,IAAI,GAAG,CAAC,MAAM,GAAG,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,+CAA+C,CAAC,CAAA;QACtG,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACrF,+FAA+F;QAC/F,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;QAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAA;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;QAEtB,IAAI,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE;YAClD,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;QAE1F,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC9B,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QACnC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QAC1B,8FAA8F;QAC9F,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAC9B,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACxC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC7B,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC7B,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QAC5B,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACpC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACnC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACpC,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC1B,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAE9B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAChC,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;QACrC,yFAAyF;QACzF,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAChC,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QAC5B,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAChC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC3C,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC/B,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC/B,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QAC9B,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACtC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACrC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACtC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC5B,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC5B,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC5B,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC5B,iFAAiF;QACjF,8FAA8F;QAC9F,kGAAkG;QAClG,OAAO,CAAC,aAAa,CAAC,QAAQ,GAAG,QAAQ,EAAE,EAAE,CAAC,CAAA;QAC9C,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACjC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAE5B,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IACpD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACzC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC5B,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IACjC,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACvB,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACvB,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACpC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACrC,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACvC,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC7B,GAAG,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAExB,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC,CAAA;AACnD,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * A CSV as a Quire database: columns with guessed types, and rows carrying values of those types.
3
+ *
4
+ * A Notion export writes one `.csv` per database — the same file you would get from a spreadsheet —
5
+ * and a CSV has no types at all. Importing every column as text is the safe answer and the useless
6
+ * one: a date column you cannot sort by date and a number column that sorts 10 before 9 are the two
7
+ * complaints a database import gets, and both are the same complaint.
8
+ *
9
+ * **So the type is guessed, and the guess is reported.** Every column contributes a sentence to the
10
+ * import report saying what it was read as and on what evidence — "Due: read as a date, from 12 of 12
11
+ * values" — because a guess nobody is told about is indistinguishable from a mistake. The rules are
12
+ * ordered from most specific to least and every one of them demands *every* non-empty value in the
13
+ * column agree; one stray `n/a` in a date column makes it text, which is the right way round. A
14
+ * column that is text is not a failure and does not say "failed": it is a column whose values did not
15
+ * all look like anything narrower.
16
+ *
17
+ * What this file does **not** do is guess a relation, a rollup, a formula or a person. Each of those
18
+ * names something outside the file — another database, another column, a member of this workspace —
19
+ * and inventing one from a string of text is how an import produces a database that looks right and
20
+ * computes nothing. They stay text, and the report says so.
21
+ */
22
+ import type { PropertyConfig, PropertyType } from '../../contract/index.js';
23
+ /**
24
+ * RFC 4180, with the two departures every real file needs.
25
+ *
26
+ * A quoted field may hold newlines and `""` for a literal quote — that part is the specification. The
27
+ * departures are that a lone `\r` or a `\r\n` both end a record (Excel writes one, Notion the other)
28
+ * and that a stray quote inside an unquoted field is a character rather than an error, because the
29
+ * alternative is refusing a file every other reader opens.
30
+ */
31
+ export declare function parseCsv(source: string): string[][];
32
+ /** `2026-01-05`, `January 5, 2026`, `05/01/2026` — as the ISO string a date cell stores. */
33
+ export declare function parseDateValue(raw: string): string | null;
34
+ /** `1,234.50`, `$99`, `12%` — as the number a numeric sort and a rollup can use. */
35
+ export declare function parseNumberValue(raw: string): {
36
+ value: number;
37
+ percent: boolean;
38
+ currency: string | null;
39
+ } | null;
40
+ export interface GuessedColumn {
41
+ name: string;
42
+ type: PropertyType;
43
+ config: PropertyConfig;
44
+ /**
45
+ * What the guess was and what it was made from, in one sentence for the report.
46
+ *
47
+ * Written here rather than at the call site because only this function knows the evidence — how
48
+ * many values agreed, how many distinct choices there were — and a reason assembled later would
49
+ * either repeat the rules or say less than it could.
50
+ */
51
+ note: string;
52
+ }
53
+ /**
54
+ * One column's type, from its values.
55
+ *
56
+ * The order is the whole algorithm: checkbox before number (`1` and `0` are both), number before
57
+ * date (a bare year is a number), url and email before select (a column of six addresses is not six
58
+ * choices), multi-select before select (a comma is the only thing that separates them), and select
59
+ * before text (the fallback that is always true).
60
+ */
61
+ export declare function guessColumn(name: string, rawValues: string[]): GuessedColumn;
62
+ /** `Design, Urgent` → `['Design', 'Urgent']`, which is how every exporter writes a multi-select. */
63
+ export declare const splitChoices: (value: string) => string[];
64
+ /**
65
+ * One cell, as the value the column's type stores.
66
+ *
67
+ * Null means "leave the key out of `props`" rather than "write null": an absent key is what every
68
+ * other writer in this module produces for an empty cell, and a null would make a `not_contains`
69
+ * filter behave differently for an imported row than for one somebody typed.
70
+ *
71
+ * `select` stores a **scalar** option id and `multi_select` an **array** of them, and the difference
72
+ * is load-bearing rather than cosmetic: `query.ts` compares a select as text through `props->>'key'`,
73
+ * so an array there stringifies to `["done"]` and matches no filter anybody can write. The cell
74
+ * component reads either shape, which is exactly why this is easy to get wrong and invisible on screen.
75
+ */
76
+ export declare function coerceValue(column: GuessedColumn, raw: string): unknown;
77
+ //# sourceMappingURL=csv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../../src/server/import/csv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAgB,MAAM,yBAAyB,CAAA;AAWzF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CA4DnD;AAeD,4FAA4F;AAC5F,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAazD;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GACV;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CASrE;AAyBD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,YAAY,CAAA;IAClB,MAAM,EAAE,cAAc,CAAA;IACtB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,aAAa,CAmF5E;AAED,oGAAoG;AACpG,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MAAM,EAIb,CAAA;AAEtC;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAwBvE"}