@noy-db/as-ndjson 0.1.0-pre.10

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vLannaAi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # @noy-db/as-ndjson
2
+
3
+ [![npm](https://img.shields.io/npm/v/%40noy-db/as-ndjson.svg)](https://www.npmjs.com/package/@noy-db/as-ndjson)
4
+
5
+ > Newline-delimited JSON export for noy-db
6
+
7
+ Part of [**`@noy-db/hub`**](https://www.npmjs.com/package/@noy-db/hub) — the zero-knowledge, offline-first, encrypted document store.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @noy-db/hub @noy-db/as-ndjson
13
+ ```
14
+
15
+ ## What it is
16
+
17
+ Newline-delimited JSON export for noy-db — streaming plaintext export suitable for data pipelines, warehouse ingestion, and jq pipelines. Gated by RFC #249 canExportPlaintext. Part of the @noy-db/as-* portable-artefact family (plaintext tier).
18
+
19
+ ## Status
20
+
21
+ **Pre-release** (`0.1.0-pre.1`). API may change before `1.0`.
22
+
23
+ ## Documentation
24
+
25
+ See the [main repository](https://github.com/vLannaAi/noy-db#readme) for setup, examples, and the full subsystem catalog.
26
+
27
+ - Source — [`packages/as-ndjson`](https://github.com/vLannaAi/noy-db/tree/main/packages/as-ndjson)
28
+ - Issues — [github.com/vLannaAi/noy-db/issues](https://github.com/vLannaAi/noy-db/issues)
29
+ - Spec — [`SPEC.md`](https://github.com/vLannaAi/noy-db/blob/main/SPEC.md)
30
+
31
+ ## License
32
+
33
+ [MIT](./LICENSE) © vLannaAi
package/dist/index.cjs ADDED
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ download: () => download,
24
+ fromString: () => fromString,
25
+ pipe: () => pipe,
26
+ stream: () => stream,
27
+ toString: () => toString
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_hub = require("@noy-db/hub");
31
+ async function* stream(vault, options = {}) {
32
+ vault.assertCanExport("plaintext", "ndjson");
33
+ const allowlist = options.collections ? new Set(options.collections) : null;
34
+ const schemaField = options.schemaField ?? "_schema";
35
+ for await (const chunk of vault.exportStream({ granularity: "record" })) {
36
+ if (allowlist && !allowlist.has(chunk.collection)) continue;
37
+ for (const record of chunk.records) {
38
+ const base = options.includeMeta ? record : stripMeta(record);
39
+ const out = { [schemaField]: chunk.collection, ...base };
40
+ yield JSON.stringify(out);
41
+ }
42
+ }
43
+ }
44
+ async function toString(vault, options = {}) {
45
+ const lines = [];
46
+ for await (const line of stream(vault, options)) lines.push(line);
47
+ return lines.join("\n");
48
+ }
49
+ async function download(vault, options = {}) {
50
+ const ndjson = await toString(vault, options);
51
+ const filename = options.filename ?? "vault-export.ndjson";
52
+ const blob = new Blob([ndjson + "\n"], { type: "application/x-ndjson;charset=utf-8" });
53
+ const url = URL.createObjectURL(blob);
54
+ const a = document.createElement("a");
55
+ a.href = url;
56
+ a.download = filename;
57
+ a.click();
58
+ URL.revokeObjectURL(url);
59
+ }
60
+ async function pipe(vault, sink, options) {
61
+ if (options.acknowledgeRisks !== true) {
62
+ throw new Error(
63
+ 'as-ndjson.pipe: acknowledgeRisks: true is required for on-disk plaintext output. See docs/patterns/as-exports.md \xA7"The three tiers of \\"plaintext out\\""'
64
+ );
65
+ }
66
+ for await (const line of stream(vault, options)) {
67
+ sink.write(line + "\n");
68
+ }
69
+ sink.end?.();
70
+ }
71
+ function stripMeta(record) {
72
+ const out = {};
73
+ for (const [key, value] of Object.entries(record)) {
74
+ if (key === "_v" || key === "_ts" || key === "_by" || key === "_iv" || key === "_data" || key === "_noydb") continue;
75
+ out[key] = value;
76
+ }
77
+ return out;
78
+ }
79
+ async function fromString(vault, ndjson, options) {
80
+ vault.assertCanImport("plaintext", "ndjson");
81
+ const policy = options.policy ?? "merge";
82
+ const idKey = options.idKey ?? "id";
83
+ const records = [];
84
+ let lineNo = 0;
85
+ for (const raw of ndjson.split("\n")) {
86
+ lineNo++;
87
+ const line = raw.trim();
88
+ if (!line) continue;
89
+ let parsed;
90
+ try {
91
+ parsed = JSON.parse(line);
92
+ } catch (err) {
93
+ throw new Error(`as-ndjson.fromString: malformed JSON on line ${lineNo}: ${err.message}`);
94
+ }
95
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
96
+ throw new Error(`as-ndjson.fromString: line ${lineNo} is not a JSON object`);
97
+ }
98
+ records.push(parsed);
99
+ }
100
+ const plan = await (0, import_hub.diffVault)(vault, { [options.collection]: records }, {
101
+ collections: [options.collection],
102
+ idKey
103
+ });
104
+ return {
105
+ plan,
106
+ policy,
107
+ async apply() {
108
+ await vault.noydb.transaction((tx) => {
109
+ const txVault = tx.vault(vault.name);
110
+ for (const entry of plan.added) {
111
+ txVault.collection(entry.collection).put(entry.id, entry.record);
112
+ }
113
+ if (policy !== "insert-only") {
114
+ for (const entry of plan.modified) {
115
+ txVault.collection(entry.collection).put(entry.id, entry.record);
116
+ }
117
+ }
118
+ if (policy === "replace") {
119
+ for (const entry of plan.deleted) {
120
+ txVault.collection(entry.collection).delete(entry.id);
121
+ }
122
+ }
123
+ });
124
+ }
125
+ };
126
+ }
127
+ // Annotate the CommonJS export names for ESM import in node:
128
+ 0 && (module.exports = {
129
+ download,
130
+ fromString,
131
+ pipe,
132
+ stream,
133
+ toString
134
+ });
135
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/as-ndjson** — newline-delimited JSON plaintext export.\n *\n * Streaming-friendly sibling to `@noy-db/as-json`. Emits one JSON\n * object per line, each carrying a `_schema` field naming the source\n * collection so a downstream reader can route records without a\n * separate header pass:\n *\n * ```\n * {\"_schema\":\"invoices\",\"id\":\"i1\",\"amount\":100,...}\n * {\"_schema\":\"invoices\",\"id\":\"i2\",\"amount\":250,...}\n * {\"_schema\":\"payments\",\"id\":\"p1\",\"invoiceId\":\"i1\",\"amount\":100,...}\n * ```\n *\n * Best for large vaults (10K+ records) where loading a single JSON\n * array into memory is clumsy. Pipes cleanly into `jq`, `fx`, log\n * stacks, or any line-oriented reducer.\n *\n * @packageDocumentation\n */\n\nimport type { Vault } from '@noy-db/hub'\n\nexport interface AsNDJSONOptions {\n /** Collection allowlist. Omit for every collection the caller can read. */\n readonly collections?: readonly string[]\n /** Include envelope metadata (`_v`, `_ts`, `_by`) on each line. Default `false`. */\n readonly includeMeta?: boolean\n /** Name of the routing field. Default `'_schema'`. */\n readonly schemaField?: string\n}\n\nexport interface AsNDJSONDownloadOptions extends AsNDJSONOptions {\n /** Filename offered to the browser. Default `'vault-export.ndjson'`. */\n readonly filename?: string\n}\n\nexport interface AsNDJSONWriteOptions extends AsNDJSONOptions {\n /** Required to write plaintext NDJSON to disk — Tier 3 risk gate. */\n readonly acknowledgeRisks: true\n}\n\n/**\n * Async iterator emitting one NDJSON-formatted line per record (no\n * trailing newline — the caller decides). The authorization check\n * runs before the first record is produced.\n */\nexport async function* stream(vault: Vault, options: AsNDJSONOptions = {}): AsyncGenerator<string> {\n vault.assertCanExport('plaintext', 'ndjson')\n const allowlist = options.collections ? new Set(options.collections) : null\n const schemaField = options.schemaField ?? '_schema'\n\n for await (const chunk of vault.exportStream({ granularity: 'record' })) {\n if (allowlist && !allowlist.has(chunk.collection)) continue\n for (const record of chunk.records) {\n const base = options.includeMeta\n ? (record as Record<string, unknown>)\n : stripMeta(record as Record<string, unknown>)\n const out: Record<string, unknown> = { [schemaField]: chunk.collection, ...base }\n yield JSON.stringify(out)\n }\n }\n}\n\n/** Collect the full NDJSON export into a single string (in-memory). */\nexport async function toString(vault: Vault, options: AsNDJSONOptions = {}): Promise<string> {\n const lines: string[] = []\n for await (const line of stream(vault, options)) lines.push(line)\n return lines.join('\\n')\n}\n\n/** Browser download wrapping `toString()` in a Blob save-as prompt. */\nexport async function download(vault: Vault, options: AsNDJSONDownloadOptions = {}): Promise<void> {\n const ndjson = await toString(vault, options)\n const filename = options.filename ?? 'vault-export.ndjson'\n const blob = new Blob([ndjson + '\\n'], { type: 'application/x-ndjson;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n\n/**\n * Node pipe: stream each line into a WritableStream-like sink (a\n * `fs.WriteStream`, `process.stdout`, or any `.write(chunk)` +\n * `.end()` duck). Memory usage is O(one record) regardless of vault\n * size.\n */\nexport async function pipe(\n vault: Vault,\n sink: { write(chunk: string): unknown; end?(): void },\n options: AsNDJSONWriteOptions,\n): Promise<void> {\n if (options.acknowledgeRisks !== true) {\n throw new Error(\n 'as-ndjson.pipe: acknowledgeRisks: true is required for on-disk plaintext output. ' +\n 'See docs/patterns/as-exports.md §\"The three tiers of \\\\\"plaintext out\\\\\"\"',\n )\n }\n for await (const line of stream(vault, options)) {\n sink.write(line + '\\n')\n }\n sink.end?.()\n}\n\nfunction stripMeta(record: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(record)) {\n if (key === '_v' || key === '_ts' || key === '_by' || key === '_iv' || key === '_data' || key === '_noydb') continue\n out[key] = value\n }\n return out\n}\n\n// ─── Reader ─────────────────────────────────────────────\n\nimport { diffVault, type VaultDiff } from '@noy-db/hub'\n\nexport type ImportPolicy = 'merge' | 'replace' | 'insert-only'\n\nexport interface AsNDJSONImportOptions {\n /**\n * Target collection. NDJSON is one record per line — every record\n * lands in the same collection. Required.\n */\n readonly collection: string\n /** Field on each record that carries its id. Default `'id'`. */\n readonly idKey?: string\n /** Reconciliation policy. Default `'merge'`. */\n readonly policy?: ImportPolicy\n}\n\nexport interface AsNDJSONImportPlan {\n readonly plan: VaultDiff\n readonly policy: ImportPolicy\n apply(): Promise<void>\n}\n\n/**\n * Parse newline-delimited JSON into records and build an import plan\n * for one collection. Empty lines and lines with leading whitespace\n * are ignored. A single malformed line throws — callers that want\n * lenient parsing can pre-filter their input.\n */\nexport async function fromString(\n vault: Vault,\n ndjson: string,\n options: AsNDJSONImportOptions,\n): Promise<AsNDJSONImportPlan> {\n vault.assertCanImport('plaintext', 'ndjson')\n const policy: ImportPolicy = options.policy ?? 'merge'\n const idKey = options.idKey ?? 'id'\n\n const records: Record<string, unknown>[] = []\n let lineNo = 0\n for (const raw of ndjson.split('\\n')) {\n lineNo++\n const line = raw.trim()\n if (!line) continue\n let parsed: unknown\n try {\n parsed = JSON.parse(line)\n } catch (err) {\n throw new Error(`as-ndjson.fromString: malformed JSON on line ${lineNo}: ${(err as Error).message}`)\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`as-ndjson.fromString: line ${lineNo} is not a JSON object`)\n }\n records.push(parsed as Record<string, unknown>)\n }\n\n const plan = await diffVault(vault, { [options.collection]: records }, {\n collections: [options.collection],\n idKey,\n })\n\n return {\n plan,\n policy,\n async apply(): Promise<void> {\n // Routes through the txStrategy seam — throws clearly when\n // withTransactions() isn't opted in. Atomicity rolls back any\n // partial writes if a put fails mid-batch.\n await vault.noydb.transaction((tx) => {\n const txVault = tx.vault(vault.name)\n for (const entry of plan.added) {\n txVault.collection(entry.collection).put(entry.id, entry.record)\n }\n if (policy !== 'insert-only') {\n for (const entry of plan.modified) {\n txVault.collection(entry.collection).put(entry.id, entry.record)\n }\n }\n if (policy === 'replace') {\n for (const entry of plan.deleted) {\n txVault.collection(entry.collection).delete(entry.id)\n }\n }\n })\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,86 @@
1
+ import { VaultDiff, Vault } from '@noy-db/hub';
2
+
3
+ /**
4
+ * **@noy-db/as-ndjson** — newline-delimited JSON plaintext export.
5
+ *
6
+ * Streaming-friendly sibling to `@noy-db/as-json`. Emits one JSON
7
+ * object per line, each carrying a `_schema` field naming the source
8
+ * collection so a downstream reader can route records without a
9
+ * separate header pass:
10
+ *
11
+ * ```
12
+ * {"_schema":"invoices","id":"i1","amount":100,...}
13
+ * {"_schema":"invoices","id":"i2","amount":250,...}
14
+ * {"_schema":"payments","id":"p1","invoiceId":"i1","amount":100,...}
15
+ * ```
16
+ *
17
+ * Best for large vaults (10K+ records) where loading a single JSON
18
+ * array into memory is clumsy. Pipes cleanly into `jq`, `fx`, log
19
+ * stacks, or any line-oriented reducer.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+
24
+ interface AsNDJSONOptions {
25
+ /** Collection allowlist. Omit for every collection the caller can read. */
26
+ readonly collections?: readonly string[];
27
+ /** Include envelope metadata (`_v`, `_ts`, `_by`) on each line. Default `false`. */
28
+ readonly includeMeta?: boolean;
29
+ /** Name of the routing field. Default `'_schema'`. */
30
+ readonly schemaField?: string;
31
+ }
32
+ interface AsNDJSONDownloadOptions extends AsNDJSONOptions {
33
+ /** Filename offered to the browser. Default `'vault-export.ndjson'`. */
34
+ readonly filename?: string;
35
+ }
36
+ interface AsNDJSONWriteOptions extends AsNDJSONOptions {
37
+ /** Required to write plaintext NDJSON to disk — Tier 3 risk gate. */
38
+ readonly acknowledgeRisks: true;
39
+ }
40
+ /**
41
+ * Async iterator emitting one NDJSON-formatted line per record (no
42
+ * trailing newline — the caller decides). The authorization check
43
+ * runs before the first record is produced.
44
+ */
45
+ declare function stream(vault: Vault, options?: AsNDJSONOptions): AsyncGenerator<string>;
46
+ /** Collect the full NDJSON export into a single string (in-memory). */
47
+ declare function toString(vault: Vault, options?: AsNDJSONOptions): Promise<string>;
48
+ /** Browser download wrapping `toString()` in a Blob save-as prompt. */
49
+ declare function download(vault: Vault, options?: AsNDJSONDownloadOptions): Promise<void>;
50
+ /**
51
+ * Node pipe: stream each line into a WritableStream-like sink (a
52
+ * `fs.WriteStream`, `process.stdout`, or any `.write(chunk)` +
53
+ * `.end()` duck). Memory usage is O(one record) regardless of vault
54
+ * size.
55
+ */
56
+ declare function pipe(vault: Vault, sink: {
57
+ write(chunk: string): unknown;
58
+ end?(): void;
59
+ }, options: AsNDJSONWriteOptions): Promise<void>;
60
+
61
+ type ImportPolicy = 'merge' | 'replace' | 'insert-only';
62
+ interface AsNDJSONImportOptions {
63
+ /**
64
+ * Target collection. NDJSON is one record per line — every record
65
+ * lands in the same collection. Required.
66
+ */
67
+ readonly collection: string;
68
+ /** Field on each record that carries its id. Default `'id'`. */
69
+ readonly idKey?: string;
70
+ /** Reconciliation policy. Default `'merge'`. */
71
+ readonly policy?: ImportPolicy;
72
+ }
73
+ interface AsNDJSONImportPlan {
74
+ readonly plan: VaultDiff;
75
+ readonly policy: ImportPolicy;
76
+ apply(): Promise<void>;
77
+ }
78
+ /**
79
+ * Parse newline-delimited JSON into records and build an import plan
80
+ * for one collection. Empty lines and lines with leading whitespace
81
+ * are ignored. A single malformed line throws — callers that want
82
+ * lenient parsing can pre-filter their input.
83
+ */
84
+ declare function fromString(vault: Vault, ndjson: string, options: AsNDJSONImportOptions): Promise<AsNDJSONImportPlan>;
85
+
86
+ export { type AsNDJSONDownloadOptions, type AsNDJSONImportOptions, type AsNDJSONImportPlan, type AsNDJSONOptions, type AsNDJSONWriteOptions, type ImportPolicy, download, fromString, pipe, stream, toString };
@@ -0,0 +1,86 @@
1
+ import { VaultDiff, Vault } from '@noy-db/hub';
2
+
3
+ /**
4
+ * **@noy-db/as-ndjson** — newline-delimited JSON plaintext export.
5
+ *
6
+ * Streaming-friendly sibling to `@noy-db/as-json`. Emits one JSON
7
+ * object per line, each carrying a `_schema` field naming the source
8
+ * collection so a downstream reader can route records without a
9
+ * separate header pass:
10
+ *
11
+ * ```
12
+ * {"_schema":"invoices","id":"i1","amount":100,...}
13
+ * {"_schema":"invoices","id":"i2","amount":250,...}
14
+ * {"_schema":"payments","id":"p1","invoiceId":"i1","amount":100,...}
15
+ * ```
16
+ *
17
+ * Best for large vaults (10K+ records) where loading a single JSON
18
+ * array into memory is clumsy. Pipes cleanly into `jq`, `fx`, log
19
+ * stacks, or any line-oriented reducer.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+
24
+ interface AsNDJSONOptions {
25
+ /** Collection allowlist. Omit for every collection the caller can read. */
26
+ readonly collections?: readonly string[];
27
+ /** Include envelope metadata (`_v`, `_ts`, `_by`) on each line. Default `false`. */
28
+ readonly includeMeta?: boolean;
29
+ /** Name of the routing field. Default `'_schema'`. */
30
+ readonly schemaField?: string;
31
+ }
32
+ interface AsNDJSONDownloadOptions extends AsNDJSONOptions {
33
+ /** Filename offered to the browser. Default `'vault-export.ndjson'`. */
34
+ readonly filename?: string;
35
+ }
36
+ interface AsNDJSONWriteOptions extends AsNDJSONOptions {
37
+ /** Required to write plaintext NDJSON to disk — Tier 3 risk gate. */
38
+ readonly acknowledgeRisks: true;
39
+ }
40
+ /**
41
+ * Async iterator emitting one NDJSON-formatted line per record (no
42
+ * trailing newline — the caller decides). The authorization check
43
+ * runs before the first record is produced.
44
+ */
45
+ declare function stream(vault: Vault, options?: AsNDJSONOptions): AsyncGenerator<string>;
46
+ /** Collect the full NDJSON export into a single string (in-memory). */
47
+ declare function toString(vault: Vault, options?: AsNDJSONOptions): Promise<string>;
48
+ /** Browser download wrapping `toString()` in a Blob save-as prompt. */
49
+ declare function download(vault: Vault, options?: AsNDJSONDownloadOptions): Promise<void>;
50
+ /**
51
+ * Node pipe: stream each line into a WritableStream-like sink (a
52
+ * `fs.WriteStream`, `process.stdout`, or any `.write(chunk)` +
53
+ * `.end()` duck). Memory usage is O(one record) regardless of vault
54
+ * size.
55
+ */
56
+ declare function pipe(vault: Vault, sink: {
57
+ write(chunk: string): unknown;
58
+ end?(): void;
59
+ }, options: AsNDJSONWriteOptions): Promise<void>;
60
+
61
+ type ImportPolicy = 'merge' | 'replace' | 'insert-only';
62
+ interface AsNDJSONImportOptions {
63
+ /**
64
+ * Target collection. NDJSON is one record per line — every record
65
+ * lands in the same collection. Required.
66
+ */
67
+ readonly collection: string;
68
+ /** Field on each record that carries its id. Default `'id'`. */
69
+ readonly idKey?: string;
70
+ /** Reconciliation policy. Default `'merge'`. */
71
+ readonly policy?: ImportPolicy;
72
+ }
73
+ interface AsNDJSONImportPlan {
74
+ readonly plan: VaultDiff;
75
+ readonly policy: ImportPolicy;
76
+ apply(): Promise<void>;
77
+ }
78
+ /**
79
+ * Parse newline-delimited JSON into records and build an import plan
80
+ * for one collection. Empty lines and lines with leading whitespace
81
+ * are ignored. A single malformed line throws — callers that want
82
+ * lenient parsing can pre-filter their input.
83
+ */
84
+ declare function fromString(vault: Vault, ndjson: string, options: AsNDJSONImportOptions): Promise<AsNDJSONImportPlan>;
85
+
86
+ export { type AsNDJSONDownloadOptions, type AsNDJSONImportOptions, type AsNDJSONImportPlan, type AsNDJSONOptions, type AsNDJSONWriteOptions, type ImportPolicy, download, fromString, pipe, stream, toString };
package/dist/index.js ADDED
@@ -0,0 +1,106 @@
1
+ // src/index.ts
2
+ import { diffVault } from "@noy-db/hub";
3
+ async function* stream(vault, options = {}) {
4
+ vault.assertCanExport("plaintext", "ndjson");
5
+ const allowlist = options.collections ? new Set(options.collections) : null;
6
+ const schemaField = options.schemaField ?? "_schema";
7
+ for await (const chunk of vault.exportStream({ granularity: "record" })) {
8
+ if (allowlist && !allowlist.has(chunk.collection)) continue;
9
+ for (const record of chunk.records) {
10
+ const base = options.includeMeta ? record : stripMeta(record);
11
+ const out = { [schemaField]: chunk.collection, ...base };
12
+ yield JSON.stringify(out);
13
+ }
14
+ }
15
+ }
16
+ async function toString(vault, options = {}) {
17
+ const lines = [];
18
+ for await (const line of stream(vault, options)) lines.push(line);
19
+ return lines.join("\n");
20
+ }
21
+ async function download(vault, options = {}) {
22
+ const ndjson = await toString(vault, options);
23
+ const filename = options.filename ?? "vault-export.ndjson";
24
+ const blob = new Blob([ndjson + "\n"], { type: "application/x-ndjson;charset=utf-8" });
25
+ const url = URL.createObjectURL(blob);
26
+ const a = document.createElement("a");
27
+ a.href = url;
28
+ a.download = filename;
29
+ a.click();
30
+ URL.revokeObjectURL(url);
31
+ }
32
+ async function pipe(vault, sink, options) {
33
+ if (options.acknowledgeRisks !== true) {
34
+ throw new Error(
35
+ 'as-ndjson.pipe: acknowledgeRisks: true is required for on-disk plaintext output. See docs/patterns/as-exports.md \xA7"The three tiers of \\"plaintext out\\""'
36
+ );
37
+ }
38
+ for await (const line of stream(vault, options)) {
39
+ sink.write(line + "\n");
40
+ }
41
+ sink.end?.();
42
+ }
43
+ function stripMeta(record) {
44
+ const out = {};
45
+ for (const [key, value] of Object.entries(record)) {
46
+ if (key === "_v" || key === "_ts" || key === "_by" || key === "_iv" || key === "_data" || key === "_noydb") continue;
47
+ out[key] = value;
48
+ }
49
+ return out;
50
+ }
51
+ async function fromString(vault, ndjson, options) {
52
+ vault.assertCanImport("plaintext", "ndjson");
53
+ const policy = options.policy ?? "merge";
54
+ const idKey = options.idKey ?? "id";
55
+ const records = [];
56
+ let lineNo = 0;
57
+ for (const raw of ndjson.split("\n")) {
58
+ lineNo++;
59
+ const line = raw.trim();
60
+ if (!line) continue;
61
+ let parsed;
62
+ try {
63
+ parsed = JSON.parse(line);
64
+ } catch (err) {
65
+ throw new Error(`as-ndjson.fromString: malformed JSON on line ${lineNo}: ${err.message}`);
66
+ }
67
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
68
+ throw new Error(`as-ndjson.fromString: line ${lineNo} is not a JSON object`);
69
+ }
70
+ records.push(parsed);
71
+ }
72
+ const plan = await diffVault(vault, { [options.collection]: records }, {
73
+ collections: [options.collection],
74
+ idKey
75
+ });
76
+ return {
77
+ plan,
78
+ policy,
79
+ async apply() {
80
+ await vault.noydb.transaction((tx) => {
81
+ const txVault = tx.vault(vault.name);
82
+ for (const entry of plan.added) {
83
+ txVault.collection(entry.collection).put(entry.id, entry.record);
84
+ }
85
+ if (policy !== "insert-only") {
86
+ for (const entry of plan.modified) {
87
+ txVault.collection(entry.collection).put(entry.id, entry.record);
88
+ }
89
+ }
90
+ if (policy === "replace") {
91
+ for (const entry of plan.deleted) {
92
+ txVault.collection(entry.collection).delete(entry.id);
93
+ }
94
+ }
95
+ });
96
+ }
97
+ };
98
+ }
99
+ export {
100
+ download,
101
+ fromString,
102
+ pipe,
103
+ stream,
104
+ toString
105
+ };
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/as-ndjson** — newline-delimited JSON plaintext export.\n *\n * Streaming-friendly sibling to `@noy-db/as-json`. Emits one JSON\n * object per line, each carrying a `_schema` field naming the source\n * collection so a downstream reader can route records without a\n * separate header pass:\n *\n * ```\n * {\"_schema\":\"invoices\",\"id\":\"i1\",\"amount\":100,...}\n * {\"_schema\":\"invoices\",\"id\":\"i2\",\"amount\":250,...}\n * {\"_schema\":\"payments\",\"id\":\"p1\",\"invoiceId\":\"i1\",\"amount\":100,...}\n * ```\n *\n * Best for large vaults (10K+ records) where loading a single JSON\n * array into memory is clumsy. Pipes cleanly into `jq`, `fx`, log\n * stacks, or any line-oriented reducer.\n *\n * @packageDocumentation\n */\n\nimport type { Vault } from '@noy-db/hub'\n\nexport interface AsNDJSONOptions {\n /** Collection allowlist. Omit for every collection the caller can read. */\n readonly collections?: readonly string[]\n /** Include envelope metadata (`_v`, `_ts`, `_by`) on each line. Default `false`. */\n readonly includeMeta?: boolean\n /** Name of the routing field. Default `'_schema'`. */\n readonly schemaField?: string\n}\n\nexport interface AsNDJSONDownloadOptions extends AsNDJSONOptions {\n /** Filename offered to the browser. Default `'vault-export.ndjson'`. */\n readonly filename?: string\n}\n\nexport interface AsNDJSONWriteOptions extends AsNDJSONOptions {\n /** Required to write plaintext NDJSON to disk — Tier 3 risk gate. */\n readonly acknowledgeRisks: true\n}\n\n/**\n * Async iterator emitting one NDJSON-formatted line per record (no\n * trailing newline — the caller decides). The authorization check\n * runs before the first record is produced.\n */\nexport async function* stream(vault: Vault, options: AsNDJSONOptions = {}): AsyncGenerator<string> {\n vault.assertCanExport('plaintext', 'ndjson')\n const allowlist = options.collections ? new Set(options.collections) : null\n const schemaField = options.schemaField ?? '_schema'\n\n for await (const chunk of vault.exportStream({ granularity: 'record' })) {\n if (allowlist && !allowlist.has(chunk.collection)) continue\n for (const record of chunk.records) {\n const base = options.includeMeta\n ? (record as Record<string, unknown>)\n : stripMeta(record as Record<string, unknown>)\n const out: Record<string, unknown> = { [schemaField]: chunk.collection, ...base }\n yield JSON.stringify(out)\n }\n }\n}\n\n/** Collect the full NDJSON export into a single string (in-memory). */\nexport async function toString(vault: Vault, options: AsNDJSONOptions = {}): Promise<string> {\n const lines: string[] = []\n for await (const line of stream(vault, options)) lines.push(line)\n return lines.join('\\n')\n}\n\n/** Browser download wrapping `toString()` in a Blob save-as prompt. */\nexport async function download(vault: Vault, options: AsNDJSONDownloadOptions = {}): Promise<void> {\n const ndjson = await toString(vault, options)\n const filename = options.filename ?? 'vault-export.ndjson'\n const blob = new Blob([ndjson + '\\n'], { type: 'application/x-ndjson;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n\n/**\n * Node pipe: stream each line into a WritableStream-like sink (a\n * `fs.WriteStream`, `process.stdout`, or any `.write(chunk)` +\n * `.end()` duck). Memory usage is O(one record) regardless of vault\n * size.\n */\nexport async function pipe(\n vault: Vault,\n sink: { write(chunk: string): unknown; end?(): void },\n options: AsNDJSONWriteOptions,\n): Promise<void> {\n if (options.acknowledgeRisks !== true) {\n throw new Error(\n 'as-ndjson.pipe: acknowledgeRisks: true is required for on-disk plaintext output. ' +\n 'See docs/patterns/as-exports.md §\"The three tiers of \\\\\"plaintext out\\\\\"\"',\n )\n }\n for await (const line of stream(vault, options)) {\n sink.write(line + '\\n')\n }\n sink.end?.()\n}\n\nfunction stripMeta(record: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(record)) {\n if (key === '_v' || key === '_ts' || key === '_by' || key === '_iv' || key === '_data' || key === '_noydb') continue\n out[key] = value\n }\n return out\n}\n\n// ─── Reader ─────────────────────────────────────────────\n\nimport { diffVault, type VaultDiff } from '@noy-db/hub'\n\nexport type ImportPolicy = 'merge' | 'replace' | 'insert-only'\n\nexport interface AsNDJSONImportOptions {\n /**\n * Target collection. NDJSON is one record per line — every record\n * lands in the same collection. Required.\n */\n readonly collection: string\n /** Field on each record that carries its id. Default `'id'`. */\n readonly idKey?: string\n /** Reconciliation policy. Default `'merge'`. */\n readonly policy?: ImportPolicy\n}\n\nexport interface AsNDJSONImportPlan {\n readonly plan: VaultDiff\n readonly policy: ImportPolicy\n apply(): Promise<void>\n}\n\n/**\n * Parse newline-delimited JSON into records and build an import plan\n * for one collection. Empty lines and lines with leading whitespace\n * are ignored. A single malformed line throws — callers that want\n * lenient parsing can pre-filter their input.\n */\nexport async function fromString(\n vault: Vault,\n ndjson: string,\n options: AsNDJSONImportOptions,\n): Promise<AsNDJSONImportPlan> {\n vault.assertCanImport('plaintext', 'ndjson')\n const policy: ImportPolicy = options.policy ?? 'merge'\n const idKey = options.idKey ?? 'id'\n\n const records: Record<string, unknown>[] = []\n let lineNo = 0\n for (const raw of ndjson.split('\\n')) {\n lineNo++\n const line = raw.trim()\n if (!line) continue\n let parsed: unknown\n try {\n parsed = JSON.parse(line)\n } catch (err) {\n throw new Error(`as-ndjson.fromString: malformed JSON on line ${lineNo}: ${(err as Error).message}`)\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`as-ndjson.fromString: line ${lineNo} is not a JSON object`)\n }\n records.push(parsed as Record<string, unknown>)\n }\n\n const plan = await diffVault(vault, { [options.collection]: records }, {\n collections: [options.collection],\n idKey,\n })\n\n return {\n plan,\n policy,\n async apply(): Promise<void> {\n // Routes through the txStrategy seam — throws clearly when\n // withTransactions() isn't opted in. Atomicity rolls back any\n // partial writes if a put fails mid-batch.\n await vault.noydb.transaction((tx) => {\n const txVault = tx.vault(vault.name)\n for (const entry of plan.added) {\n txVault.collection(entry.collection).put(entry.id, entry.record)\n }\n if (policy !== 'insert-only') {\n for (const entry of plan.modified) {\n txVault.collection(entry.collection).put(entry.id, entry.record)\n }\n }\n if (policy === 'replace') {\n for (const entry of plan.deleted) {\n txVault.collection(entry.collection).delete(entry.id)\n }\n }\n })\n },\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@noy-db/as-ndjson",
3
+ "version": "0.1.0-pre.10",
4
+ "description": "Newline-delimited JSON export for noy-db — streaming plaintext export suitable for data pipelines, warehouse ingestion, and jq pipelines. Gated by RFC #249 canExportPlaintext. Part of the @noy-db/as-* portable-artefact family (plaintext tier).",
5
+ "license": "MIT",
6
+ "author": "vLannaAi <vicio@lanna.ai>",
7
+ "homepage": "https://github.com/vLannaAi/noy-db/tree/main/packages/as-ndjson#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/vLannaAi/noy-db.git",
11
+ "directory": "packages/as-ndjson"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/vLannaAi/noy-db/issues"
15
+ },
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": {
20
+ "import": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "require": {
25
+ "types": "./dist/index.d.cts",
26
+ "default": "./dist/index.cjs"
27
+ }
28
+ }
29
+ },
30
+ "main": "./dist/index.cjs",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@noy-db/hub": "0.1.0-pre.10"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^22.0.0",
46
+ "@noy-db/hub": "0.1.0-pre.10"
47
+ },
48
+ "keywords": [
49
+ "noy-db",
50
+ "as-ndjson",
51
+ "ndjson",
52
+ "streaming",
53
+ "export",
54
+ "plaintext",
55
+ "zero-knowledge"
56
+ ],
57
+ "publishConfig": {
58
+ "access": "public",
59
+ "tag": "latest"
60
+ },
61
+ "scripts": {
62
+ "build": "tsup",
63
+ "test": "vitest run",
64
+ "lint": "eslint src/",
65
+ "typecheck": "tsc --noEmit"
66
+ }
67
+ }