wiki-graph-sdk 0.7.0 → 0.7.1

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 CHANGED
@@ -27,6 +27,22 @@ Job event subscriptions observe durable work without coupling observation to
27
27
  cancellation. Call `job.cancel()` explicitly to cancel a job; unsubscribing
28
28
  only stops the current listener.
29
29
 
30
+ Services that receive chapter job artifacts as files can apply an ordered,
31
+ lazy sequence through the Node delivery boundary without importing Core:
32
+
33
+ ```ts
34
+ import { applyWikiGraphJobArtifacts } from "wiki-graph-sdk/worker";
35
+
36
+ await applyWikiGraphJobArtifacts({
37
+ artifacts,
38
+ stateDir: "/tmp/job/sdk-state",
39
+ wikgPath: "/tmp/job/archive.wikg",
40
+ });
41
+ ```
42
+
43
+ Each artifact carries its chapter, job kind, and source revision. The operation
44
+ stops before consuming later artifacts when a revision no longer matches.
45
+
30
46
  The SDK intentionally has no `execute(command, args)` API. CLI argument
31
47
  parsing, help text, terminal formatting, JSON, and JSONL rendering belong to
32
48
  the `wiki-graph` package. SDK methods return typed objects and job events.
package/dist/archives.cjs CHANGED
@@ -40,15 +40,18 @@ __export(archive_exports, {
40
40
  module.exports = __toCommonJS(archive_exports);
41
41
 
42
42
  // src/archive/archive.ts
43
- var import_crypto = require("crypto");
43
+ var import_crypto2 = require("crypto");
44
44
  var import_promises3 = require("fs/promises");
45
45
  var import_os3 = require("os");
46
- var import_path3 = require("path");
46
+ var import_path4 = require("path");
47
47
  var import_stream = require("stream");
48
48
  var import_wiki_graph_core5 = require("wiki-graph-core");
49
49
 
50
50
  // src/conversions.ts
51
+ var import_crypto = require("crypto");
52
+ var import_fs = require("fs");
51
53
  var import_promises2 = require("fs/promises");
54
+ var import_path3 = require("path");
52
55
  var import_wiki_graph_core2 = require("wiki-graph-core");
53
56
 
54
57
  // src/llm.ts
@@ -1269,6 +1272,9 @@ var WikiGraphConversionManager = class {
1269
1272
  if (options.targetStage !== void 0 && options.output.format !== "wikg") {
1270
1273
  throw new Error("targetStage is only supported for wikg output.");
1271
1274
  }
1275
+ if (options.output.format === "pcex") {
1276
+ throw new Error("pcex is supported only as a conversion input.");
1277
+ }
1272
1278
  if (options.targetStage !== void 0 && options.input.format === "wikg") {
1273
1279
  throw new Error(
1274
1280
  "targetStage is only supported when creating a wikg archive."
@@ -1287,7 +1293,13 @@ var WikiGraphConversionManager = class {
1287
1293
  options.digestDirectory,
1288
1294
  requiresDigest
1289
1295
  );
1296
+ let chapterCount;
1290
1297
  const write = async (archive) => {
1298
+ if (requiresDigest) await options.onSourceImported?.();
1299
+ if (typeof archive.readToc === "function") {
1300
+ const toc = await archive.readToc();
1301
+ chapterCount = toc === void 0 ? void 0 : countTocChapters(toc.items);
1302
+ }
1291
1303
  await writeArchive(archive, options.output.path, options.output.format);
1292
1304
  };
1293
1305
  if (options.input.format === "wikg") {
@@ -1320,16 +1332,28 @@ var WikiGraphConversionManager = class {
1320
1332
  };
1321
1333
  if (options.input.format === "epub") {
1322
1334
  await app.digestEpubSession(digestOptions, write);
1335
+ } else if (options.input.format === "pcex") {
1336
+ await app.digestPcexSession(
1337
+ {
1338
+ ...digestOptions,
1339
+ pdfDigest: options.input.sourcePdf.digest,
1340
+ ...options.input.sourcePdf.name === void 0 ? {} : { pdfName: options.input.sourcePdf.name }
1341
+ },
1342
+ write
1343
+ );
1323
1344
  } else if (options.input.format === "markdown") {
1324
1345
  await app.digestMarkdownSession(digestOptions, write);
1325
1346
  } else {
1326
1347
  await app.digestTxtSession(digestOptions, write);
1327
1348
  }
1328
1349
  }
1350
+ const sourceArtifact = await resolveSourceArtifact(options.input);
1329
1351
  return {
1352
+ ...chapterCount === void 0 ? {} : { chapterCount },
1330
1353
  inputFormat: options.input.format,
1331
1354
  outputFormat: options.output.format,
1332
- outputPath: options.output.path
1355
+ outputPath: options.output.path,
1356
+ ...sourceArtifact === void 0 ? {} : { sourceArtifact }
1333
1357
  };
1334
1358
  }
1335
1359
  };
@@ -1345,8 +1369,48 @@ async function writeArchive(archive, path, format) {
1345
1369
  const file = new NodeFile(resolveWikiGraphRuntimePath(path));
1346
1370
  if (format === "epub") await archive.exportEpub(file);
1347
1371
  else if (format === "wikg") await archive.saveAs(file);
1372
+ else if (format === "pcex") throw new Error("pcex output is not supported.");
1348
1373
  else await archive.exportText(file);
1349
1374
  }
1375
+ async function resolveSourceArtifact(input) {
1376
+ if (!("path" in input) || input.format === "wikg") return void 0;
1377
+ if (input.format === "pcex") {
1378
+ return {
1379
+ digest: input.sourcePdf.digest.trim().toLowerCase(),
1380
+ mediaType: "application/pdf",
1381
+ ...input.sourcePdf.name === void 0 ? {} : { name: input.sourcePdf.name }
1382
+ };
1383
+ }
1384
+ if (input.format !== "epub") return void 0;
1385
+ const path = resolveWikiGraphRuntimePath(input.path);
1386
+ const hash = (0, import_crypto.createHash)("sha256");
1387
+ try {
1388
+ for await (const chunk of (0, import_fs.createReadStream)(path)) {
1389
+ hash.update(chunk);
1390
+ }
1391
+ } catch (error) {
1392
+ if (isNodeErrorCode(error, "ENOENT")) return void 0;
1393
+ throw error;
1394
+ }
1395
+ return {
1396
+ digest: hash.digest("hex"),
1397
+ mediaType: "application/epub+zip",
1398
+ name: (0, import_path3.basename)(path)
1399
+ };
1400
+ }
1401
+ function isNodeErrorCode(error, code) {
1402
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
1403
+ }
1404
+ function countTocChapters(items) {
1405
+ let count = 0;
1406
+ for (const item of items) {
1407
+ if (item.serialId !== void 0) count += 1;
1408
+ count += countTocChapters(
1409
+ item.children
1410
+ );
1411
+ }
1412
+ return count;
1413
+ }
1350
1414
 
1351
1415
  // src/query-runtime.ts
1352
1416
  var import_wiki_graph_core3 = require("wiki-graph-core");
@@ -2019,9 +2083,9 @@ var WikiGraphArchiveManager = class {
2019
2083
  if (options.replace !== true && await nodePathExists(path)) {
2020
2084
  throw new WikiGraphArchiveExistsError(path);
2021
2085
  }
2022
- const outputPath = (0, import_path3.join)(
2023
- (0, import_path3.dirname)(path),
2024
- `.${(0, import_path3.basename)(path)}.${(0, import_crypto.randomUUID)()}.tmp.wikg`
2086
+ const outputPath = (0, import_path4.join)(
2087
+ (0, import_path4.dirname)(path),
2088
+ `.${(0, import_path4.basename)(path)}.${(0, import_crypto2.randomUUID)()}.tmp.wikg`
2025
2089
  );
2026
2090
  try {
2027
2091
  if (options.importPath === void 0) {
@@ -2664,7 +2728,7 @@ function createPathLocation(path) {
2664
2728
  }
2665
2729
  async function createEmptyArchiveFile(path) {
2666
2730
  const directoryPath = await (0, import_promises3.mkdtemp)(
2667
- (0, import_path3.join)((0, import_os3.tmpdir)(), "wikigraph-archive-write-")
2731
+ (0, import_path4.join)((0, import_os3.tmpdir)(), "wikigraph-archive-write-")
2668
2732
  );
2669
2733
  try {
2670
2734
  const directory = new NodeDirectory(directoryPath);