@gobing-ai/ts-llm-jsonl-importer 0.4.5 → 0.4.7
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/README.md +10 -0
- package/dist/importer.d.ts.map +1 -1
- package/dist/importer.js +25 -6
- package/package.json +4 -4
- package/src/importer.ts +26 -7
package/README.md
CHANGED
|
@@ -56,6 +56,16 @@ result.skippedDuplicates;
|
|
|
56
56
|
|
|
57
57
|
All modes preserve parse and validation issues in the returned `ImportResult`; malformed rows are not inserted.
|
|
58
58
|
|
|
59
|
+
## Streaming
|
|
60
|
+
|
|
61
|
+
The importer uses `FileSystem.readFileStream` when available (ADR-021), reading one line at a time
|
|
62
|
+
for **O(line) memory usage** — enabling multi-MB or multi-GB LLM history files without buffering
|
|
63
|
+
the entire file. Behavior is identical to the previous `readFile` + split approach (same `source_line`
|
|
64
|
+
values, same `ImportResult`).
|
|
65
|
+
|
|
66
|
+
When `readFileStream` is unavailable (e.g. Cloudflare Workers), the importer falls back to
|
|
67
|
+
`readFile` + split transparently.
|
|
68
|
+
|
|
59
69
|
## Import Specific Files
|
|
60
70
|
|
|
61
71
|
```ts
|
package/dist/importer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAER,aAAa,EACb,YAAY,EAEZ,cAAc,EAGjB,MAAM,SAAS,CAAC;AAajB,0DAA0D;AAC1D,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrF;AAED,+DAA+D;AAC/D,wBAAsB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAER,aAAa,EACb,YAAY,EAEZ,cAAc,EAGjB,MAAM,SAAS,CAAC;AAajB,0DAA0D;AAC1D,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrF;AAED,+DAA+D;AAC/D,wBAAsB,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA4G1G"}
|
package/dist/importer.js
CHANGED
|
@@ -32,11 +32,11 @@ export async function runJsonlImport(source, options) {
|
|
|
32
32
|
let checkpointUpdates = 0;
|
|
33
33
|
for (const file of files) {
|
|
34
34
|
const checkpoint = mode === 'incremental' ? await readCheckpoint(options.db, source, file) : 0;
|
|
35
|
-
|
|
36
|
-
for (
|
|
37
|
-
|
|
38
|
-
const line =
|
|
39
|
-
if (line
|
|
35
|
+
let lineNumber = 0;
|
|
36
|
+
for await (const rawLine of readLines(fileSystem, file)) {
|
|
37
|
+
lineNumber += 1;
|
|
38
|
+
const line = rawLine.trim();
|
|
39
|
+
if (line.length === 0 || lineNumber <= checkpoint)
|
|
40
40
|
continue;
|
|
41
41
|
processedLines += 1;
|
|
42
42
|
const raw = parseJsonLine(line, file, lineNumber, parseErrors);
|
|
@@ -209,7 +209,8 @@ async function ledgerExists(db, recordHash) {
|
|
|
209
209
|
async function insertRecord(db, targetTable, recordHash, sourceFile, sourceLine, splitIndex, payload, now) {
|
|
210
210
|
const table = targetTableFor(targetTable);
|
|
211
211
|
await db.run(`INSERT INTO ${table} (record_hash, source_file, source_line, split_index, payload_json, imported_at)
|
|
212
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
212
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
213
|
+
ON CONFLICT(record_hash) DO NOTHING`, recordHash, sourceFile, sourceLine, splitIndex, JSON.stringify(payload), timestamp(now));
|
|
213
214
|
}
|
|
214
215
|
async function insertLedger(db, recordHash, source, sourceFile, sourceLine, splitIndex, targetTable, now) {
|
|
215
216
|
await db.run(`INSERT INTO history_import_ledger (record_hash, source, source_file, source_line, split_index, target_table, imported_at)
|
|
@@ -224,3 +225,21 @@ function targetTableFor(table) {
|
|
|
224
225
|
function timestamp(now) {
|
|
225
226
|
return (now?.() ?? new Date()).toISOString();
|
|
226
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Yield lines from a file, streaming when the FileSystem supports it.
|
|
230
|
+
*
|
|
231
|
+
* WHY: large JSONL history files (100MB+) must not be loaded into memory all at
|
|
232
|
+
* once. When `fileSystem.readFileStream` is available, lines are streamed from
|
|
233
|
+
* disk in chunks. Otherwise, falls back to `readFile` + `split` — same behavior
|
|
234
|
+
* as before, preserving parity for stubs like CF Workers.
|
|
235
|
+
*/
|
|
236
|
+
async function* readLines(fileSystem, file) {
|
|
237
|
+
if (fileSystem.readFileStream) {
|
|
238
|
+
yield* fileSystem.readFileStream(file);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const content = await fileSystem.readFile(file);
|
|
242
|
+
for (const line of content.split(/\r?\n/)) {
|
|
243
|
+
yield line;
|
|
244
|
+
}
|
|
245
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-llm-jsonl-importer",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "@gobing-ai/ts-llm-jsonl-importer — Generic JSONL importer for LLM agent history files.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-llm-jsonl-importer-v<version> && git push --tags' && exit 1"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@gobing-ai/ts-db": "^0.4.
|
|
51
|
-
"@gobing-ai/ts-runtime": "^0.4.
|
|
52
|
-
"@gobing-ai/ts-utils": "^0.4.
|
|
50
|
+
"@gobing-ai/ts-db": "^0.4.7",
|
|
51
|
+
"@gobing-ai/ts-runtime": "^0.4.7",
|
|
52
|
+
"@gobing-ai/ts-utils": "^0.4.7",
|
|
53
53
|
"zod": "^4.1.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
package/src/importer.ts
CHANGED
|
@@ -56,12 +56,11 @@ export async function runJsonlImport(source: LlmJsonlSource, options: ImportOpti
|
|
|
56
56
|
|
|
57
57
|
for (const file of files) {
|
|
58
58
|
const checkpoint = mode === 'incremental' ? await readCheckpoint(options.db, source, file) : 0;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
if (line === undefined || line.length === 0 || lineNumber <= checkpoint) continue;
|
|
59
|
+
let lineNumber = 0;
|
|
60
|
+
for await (const rawLine of readLines(fileSystem, file)) {
|
|
61
|
+
lineNumber += 1;
|
|
62
|
+
const line = rawLine.trim();
|
|
63
|
+
if (line.length === 0 || lineNumber <= checkpoint) continue;
|
|
65
64
|
processedLines += 1;
|
|
66
65
|
|
|
67
66
|
const raw = parseJsonLine(line, file, lineNumber, parseErrors);
|
|
@@ -298,7 +297,8 @@ async function insertRecord(
|
|
|
298
297
|
const table = targetTableFor(targetTable);
|
|
299
298
|
await db.run(
|
|
300
299
|
`INSERT INTO ${table} (record_hash, source_file, source_line, split_index, payload_json, imported_at)
|
|
301
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
300
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
301
|
+
ON CONFLICT(record_hash) DO NOTHING`,
|
|
302
302
|
recordHash,
|
|
303
303
|
sourceFile,
|
|
304
304
|
sourceLine,
|
|
@@ -341,3 +341,22 @@ function targetTableFor(table: string): string {
|
|
|
341
341
|
function timestamp(now: ImportOptions['now']): string {
|
|
342
342
|
return (now?.() ?? new Date()).toISOString();
|
|
343
343
|
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Yield lines from a file, streaming when the FileSystem supports it.
|
|
347
|
+
*
|
|
348
|
+
* WHY: large JSONL history files (100MB+) must not be loaded into memory all at
|
|
349
|
+
* once. When `fileSystem.readFileStream` is available, lines are streamed from
|
|
350
|
+
* disk in chunks. Otherwise, falls back to `readFile` + `split` — same behavior
|
|
351
|
+
* as before, preserving parity for stubs like CF Workers.
|
|
352
|
+
*/
|
|
353
|
+
async function* readLines(fileSystem: FileSystem, file: string): AsyncGenerator<string> {
|
|
354
|
+
if (fileSystem.readFileStream) {
|
|
355
|
+
yield* fileSystem.readFileStream(file);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const content = await fileSystem.readFile(file);
|
|
359
|
+
for (const line of content.split(/\r?\n/)) {
|
|
360
|
+
yield line;
|
|
361
|
+
}
|
|
362
|
+
}
|