wiki-graph-sdk 0.7.1 → 0.8.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.
Files changed (58) hide show
  1. package/README.md +22 -1
  2. package/dist/archives.cjs +494 -656
  3. package/dist/archives.cjs.map +1 -1
  4. package/dist/archives.d.ts +48 -80
  5. package/dist/archives.js +431 -585
  6. package/dist/archives.js.map +1 -1
  7. package/dist/conversions.cjs +183 -33
  8. package/dist/conversions.cjs.map +1 -1
  9. package/dist/conversions.d.ts +8 -1
  10. package/dist/conversions.js +188 -29
  11. package/dist/conversions.js.map +1 -1
  12. package/dist/default-worker.cjs +322 -62
  13. package/dist/default-worker.cjs.map +1 -1
  14. package/dist/default-worker.d.ts +1 -0
  15. package/dist/default-worker.js +336 -60
  16. package/dist/default-worker.js.map +1 -1
  17. package/dist/embedding.cjs +2 -1
  18. package/dist/embedding.cjs.map +1 -1
  19. package/dist/embedding.d.ts +4 -4
  20. package/dist/embedding.js +2 -1
  21. package/dist/embedding.js.map +1 -1
  22. package/dist/index.cjs +1295 -949
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.ts +58 -24
  25. package/dist/index.js +1164 -805
  26. package/dist/index.js.map +1 -1
  27. package/dist/{jobs-Dd5PMSId.d.ts → jobs-CRK-DZ40.d.ts} +27 -14
  28. package/dist/local-config.cjs +2 -1
  29. package/dist/local-config.cjs.map +1 -1
  30. package/dist/local-config.js +2 -1
  31. package/dist/local-config.js.map +1 -1
  32. package/dist/maintenance.cjs +140 -30
  33. package/dist/maintenance.cjs.map +1 -1
  34. package/dist/maintenance.d.ts +5 -1
  35. package/dist/maintenance.js +145 -26
  36. package/dist/maintenance.js.map +1 -1
  37. package/dist/runtime-config.cjs +4 -3
  38. package/dist/runtime-config.cjs.map +1 -1
  39. package/dist/runtime-config.d.ts +4 -1
  40. package/dist/runtime-config.js +4 -3
  41. package/dist/runtime-config.js.map +1 -1
  42. package/dist/stage-BnWI3Rqt.d.ts +33 -0
  43. package/dist/stage.cjs +22 -12
  44. package/dist/stage.cjs.map +1 -1
  45. package/dist/stage.d.ts +2 -14
  46. package/dist/stage.js +22 -12
  47. package/dist/stage.js.map +1 -1
  48. package/dist/target-CZ7elwmj.d.ts +14 -0
  49. package/dist/wikispine.cjs +14 -10
  50. package/dist/wikispine.cjs.map +1 -1
  51. package/dist/wikispine.js +14 -10
  52. package/dist/wikispine.js.map +1 -1
  53. package/dist/worker.cjs +295 -25
  54. package/dist/worker.cjs.map +1 -1
  55. package/dist/worker.d.ts +28 -5
  56. package/dist/worker.js +313 -28
  57. package/dist/worker.js.map +1 -1
  58. package/package.json +2 -2
@@ -36,9 +36,9 @@ __export(conversions_exports, {
36
36
  module.exports = __toCommonJS(conversions_exports);
37
37
  var import_crypto = require("crypto");
38
38
  var import_fs = require("fs");
39
- var import_promises2 = require("fs/promises");
40
- var import_path3 = require("path");
41
- var import_wiki_graph_core2 = require("wiki-graph-core");
39
+ var import_promises3 = require("fs/promises");
40
+ var import_path4 = require("path");
41
+ var import_wiki_graph_core3 = require("wiki-graph-core");
42
42
 
43
43
  // src/llm.ts
44
44
  var import_anthropic = require("@ai-sdk/anthropic");
@@ -339,6 +339,14 @@ function decodeNodeResourceIdentity(identity, kind) {
339
339
  return void 0;
340
340
  }
341
341
  }
342
+ function getNodeResourcePath(resource) {
343
+ const brandedPath = getBrandedNodeResourcePath(resource, resource.kind);
344
+ if (brandedPath !== void 0) return brandedPath;
345
+ if (typeof resource === "object" && resource !== null && "path" in resource && typeof resource.path === "string") {
346
+ return resource.path;
347
+ }
348
+ throw new TypeError("Expected a Node File or Directory resource");
349
+ }
342
350
  function assertChildName(name) {
343
351
  if (name.length === 0 || name === "." || name === ".." || pathModule.isAbsolute(name) || name.includes("/") || name.includes("\\")) {
344
352
  throw new TypeError(`Directory child must be a relative name: ${name}`);
@@ -350,42 +358,42 @@ var NodeDatabaseConnection = class {
350
358
  }
351
359
  database;
352
360
  async close() {
353
- await new Promise((resolve3, reject) => {
361
+ await new Promise((resolve4, reject) => {
354
362
  this.database.close((error) => {
355
363
  if (error) reject(error);
356
- else resolve3();
364
+ else resolve4();
357
365
  });
358
366
  });
359
367
  }
360
368
  async execute(sql) {
361
- await new Promise((resolve3, reject) => {
369
+ await new Promise((resolve4, reject) => {
362
370
  this.database.exec(sql, (error) => {
363
371
  if (error) reject(error);
364
- else resolve3();
372
+ else resolve4();
365
373
  });
366
374
  });
367
375
  }
368
376
  async queryAll(sql, params = []) {
369
- return await new Promise((resolve3, reject) => {
377
+ return await new Promise((resolve4, reject) => {
370
378
  this.database.all(sql, [...params], (error, rows) => {
371
379
  if (error) reject(error);
372
- else resolve3(rows);
380
+ else resolve4(rows);
373
381
  });
374
382
  });
375
383
  }
376
384
  async queryOne(sql, params = []) {
377
- return await new Promise((resolve3, reject) => {
385
+ return await new Promise((resolve4, reject) => {
378
386
  this.database.get(sql, [...params], (error, row) => {
379
387
  if (error) reject(error);
380
- else resolve3(row);
388
+ else resolve4(row);
381
389
  });
382
390
  });
383
391
  }
384
392
  async run(sql, params = []) {
385
- await new Promise((resolve3, reject) => {
393
+ await new Promise((resolve4, reject) => {
386
394
  this.database.run(sql, [...params], (error) => {
387
395
  if (error) reject(error);
388
- else resolve3();
396
+ else resolve4();
389
397
  });
390
398
  });
391
399
  }
@@ -399,10 +407,10 @@ async function openNativeNodeDatabase(file, flags) {
399
407
  if (path === void 0) {
400
408
  throw new TypeError("The Node database adapter requires a NodeFile");
401
409
  }
402
- return await new Promise((resolve3, reject) => {
410
+ return await new Promise((resolve4, reject) => {
403
411
  const database = new nodeSqlite3.Database(path, flags, (error) => {
404
412
  if (error) reject(error);
405
- else resolve3(database);
413
+ else resolve4(database);
406
414
  });
407
415
  });
408
416
  }
@@ -411,19 +419,19 @@ async function openNodeZip(file) {
411
419
  if (path === void 0) {
412
420
  throw new TypeError("The Node ZIP adapter requires a NodeFile");
413
421
  }
414
- const zipFile = await new Promise((resolve3, reject) => {
422
+ const zipFile = await new Promise((resolve4, reject) => {
415
423
  yauzl.open(
416
424
  path,
417
425
  { autoClose: false, lazyEntries: true },
418
426
  (error, opened) => {
419
427
  if (error || opened === void 0)
420
428
  reject(error ?? new Error("Cannot open ZIP"));
421
- else resolve3(opened);
429
+ else resolve4(opened);
422
430
  }
423
431
  );
424
432
  });
425
433
  const entries = await new Promise(
426
- (resolve3, reject) => {
434
+ (resolve4, reject) => {
427
435
  const discovered = /* @__PURE__ */ new Map();
428
436
  const rejectAndClose = (error) => {
429
437
  zipFile.close();
@@ -433,7 +441,7 @@ async function openNodeZip(file) {
433
441
  };
434
442
  const resolveEntries = () => {
435
443
  zipFile.off("error", rejectAndClose);
436
- resolve3(discovered);
444
+ resolve4(discovered);
437
445
  };
438
446
  zipFile.on("entry", (entry) => {
439
447
  if (!entry.fileName.endsWith("/")) {
@@ -543,12 +551,12 @@ async function collectDecodedNodeStreamRange(input, offset, length) {
543
551
  return Buffer.concat(chunks, collected);
544
552
  }
545
553
  async function openNodeZipEntryStream(zipFile, entry, options) {
546
- return await new Promise((resolve3, reject) => {
554
+ return await new Promise((resolve4, reject) => {
547
555
  const callback = (error, opened) => {
548
556
  if (error || opened === void 0) {
549
557
  reject(error ?? new Error(`Cannot read ZIP entry: ${entry.fileName}`));
550
558
  } else {
551
- resolve3(opened);
559
+ resolve4(opened);
552
560
  }
553
561
  };
554
562
  if (options === void 0) zipFile.openReadStream(entry, callback);
@@ -679,11 +687,11 @@ async function writeNodeStream(input, writer) {
679
687
  );
680
688
  }
681
689
  async function collectNodeStream(input) {
682
- return await new Promise((resolve3, reject) => {
690
+ return await new Promise((resolve4, reject) => {
683
691
  const chunks = [];
684
692
  input.on("data", (chunk) => chunks.push(chunk));
685
693
  input.once("error", reject);
686
- input.once("end", () => resolve3(Buffer.concat(chunks)));
694
+ input.once("end", () => resolve4(Buffer.concat(chunks)));
687
695
  });
688
696
  }
689
697
  var nodeWikiGraphPlatform = {
@@ -804,12 +812,16 @@ function getWikiGraphSDKRuntimeContext() {
804
812
  return runtimeContext.getStore() ?? {
805
813
  cwd: process.cwd(),
806
814
  env: process.env,
807
- envPolicy: "production"
815
+ envPolicy: "production",
816
+ providers: {}
808
817
  };
809
818
  }
810
819
  function getWikiGraphSDKStateDir() {
811
820
  return getWikiGraphSDKRuntimeContext().stateDir;
812
821
  }
822
+ function getWikiGraphSDKProviders() {
823
+ return getWikiGraphSDKRuntimeContext().providers ?? {};
824
+ }
813
825
 
814
826
  // src/local-config.ts
815
827
  var import_path = require("path");
@@ -1027,8 +1039,8 @@ var inlineLLMConfigSchema = import_zod.z.object({
1027
1039
  });
1028
1040
  async function loadWikiGraphRuntimeConfig(options) {
1029
1041
  const [embedding, localLLM, concurrent, wikimedia, wikispine] = await Promise.all([
1030
- readLocalConfigSection("embeddings"),
1031
- readLocalConfigSection("llm"),
1042
+ options?.skipEmbeddingConfig === true ? Promise.resolve({}) : readLocalConfigSection("embeddings"),
1043
+ options?.skipLLMConfig === true ? Promise.resolve({}) : readLocalConfigSection("llm"),
1032
1044
  readLocalConfigSection("concurrent"),
1033
1045
  readLocalConfigSection("wikimedia"),
1034
1046
  readLocalConfigSection("wikispine")
@@ -1224,6 +1236,14 @@ function formatError2(error) {
1224
1236
  return error instanceof Error ? error.message : String(error);
1225
1237
  }
1226
1238
 
1239
+ // src/providers.ts
1240
+ function resolveWikiGraphLLMJSON(options) {
1241
+ if (options.llm !== void 0 && options.llmJSON !== void 0) {
1242
+ throw new Error("Pass either llm or llmJSON, not both.");
1243
+ }
1244
+ return options.llm === void 0 ? options.llmJSON : JSON.stringify(options.llm);
1245
+ }
1246
+
1227
1247
  // src/runtime-path.ts
1228
1248
  var import_os2 = require("os");
1229
1249
  var import_path2 = require("path");
@@ -1236,6 +1256,107 @@ function resolveWikiGraphRuntimePath(path) {
1236
1256
  return (0, import_path2.isAbsolute)(path) ? path : (0, import_path2.resolve)(context.cwd, path);
1237
1257
  }
1238
1258
 
1259
+ // src/archive/target.ts
1260
+ var import_promises2 = require("fs/promises");
1261
+ var import_path3 = require("path");
1262
+ var import_wiki_graph_core2 = require("wiki-graph-core");
1263
+ var WikiGraphArchiveOwnershipError = class extends Error {
1264
+ code = "WIKI_GRAPH_ARCHIVE_OWNERSHIP_MISMATCH";
1265
+ constructor(message) {
1266
+ super(message);
1267
+ this.name = "WikiGraphArchiveOwnershipError";
1268
+ }
1269
+ };
1270
+ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1271
+ const path = resolveWikiGraphRuntimePath(inputPath);
1272
+ const candidate = await canonicalPath(path);
1273
+ const candidateIdentity = await readFileIdentity(path);
1274
+ const libraries = await (0, import_wiki_graph_core2.listWikiGraphLibraries)();
1275
+ const matches = await findMatchingMembers(
1276
+ libraries,
1277
+ candidate,
1278
+ candidateIdentity
1279
+ );
1280
+ if (matches.length > 0) {
1281
+ const match = requireUnambiguousManagedMatch(path, matches);
1282
+ throw new WikiGraphArchiveOwnershipError(
1283
+ `Standalone archive path belongs to registered library ${(0, import_wiki_graph_core2.formatWikiGraphLibraryUri)(
1284
+ match.library.isDefault ? void 0 : match.library.publicId
1285
+ )}: ${path}. Use the library UUID URI ${match.archive.uri} instead.`
1286
+ );
1287
+ }
1288
+ for (const library of libraries) {
1289
+ const rootPath = getNodeResourcePath(library.folder);
1290
+ const root = await canonicalPath(rootPath);
1291
+ if (!isWithin(root, candidate)) continue;
1292
+ throw new WikiGraphArchiveOwnershipError(
1293
+ `Standalone archive path belongs to registered library ${(0, import_wiki_graph_core2.formatWikiGraphLibraryUri)(
1294
+ library.isDefault ? void 0 : library.publicId
1295
+ )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1296
+ );
1297
+ }
1298
+ return path;
1299
+ }
1300
+ async function canonicalPath(path) {
1301
+ try {
1302
+ return await (0, import_promises2.realpath)(path);
1303
+ } catch {
1304
+ const absolute = (0, import_path3.resolve)(path);
1305
+ const parent = (0, import_path3.dirname)(absolute);
1306
+ return parent === absolute ? absolute : (0, import_path3.join)(await canonicalPath(parent), (0, import_path3.basename)(absolute));
1307
+ }
1308
+ }
1309
+ function isWithin(root, candidate) {
1310
+ const child = (0, import_path3.relative)(root, candidate);
1311
+ return child === "" || !child.startsWith("..") && !(0, import_path3.isAbsolute)(child);
1312
+ }
1313
+ async function findMatchingMembers(libraries, candidate, candidateIdentity) {
1314
+ const members = [];
1315
+ for (const library of libraries) {
1316
+ const archives = await (0, import_wiki_graph_core2.listWikiGraphLibraryArchives)({
1317
+ isDefault: library.isDefault,
1318
+ kind: "scope",
1319
+ ...library.isDefault ? {} : { publicId: library.publicId }
1320
+ });
1321
+ for (const archive of archives) {
1322
+ if (archive.file === void 0) continue;
1323
+ members.push({
1324
+ archive,
1325
+ library,
1326
+ memberPath: getNodeResourcePath(archive.file)
1327
+ });
1328
+ }
1329
+ }
1330
+ const exact = [];
1331
+ for (const member of members) {
1332
+ if (await canonicalPath(member.memberPath) === candidate) {
1333
+ exact.push(member);
1334
+ }
1335
+ }
1336
+ if (exact.length > 0 || candidateIdentity === void 0) return exact;
1337
+ const identityMatches = [];
1338
+ for (const member of members) {
1339
+ if (await readFileIdentity(member.memberPath) === candidateIdentity) {
1340
+ identityMatches.push(member);
1341
+ }
1342
+ }
1343
+ return identityMatches;
1344
+ }
1345
+ function requireUnambiguousManagedMatch(path, matches) {
1346
+ if (matches.length === 1) return matches[0];
1347
+ throw new WikiGraphArchiveOwnershipError(
1348
+ `Archive file identity is ambiguous across managed archives: ${path}. Use an explicit library UUID URI (${matches.map((match) => match.archive.uri).join(", ")}).`
1349
+ );
1350
+ }
1351
+ async function readFileIdentity(path) {
1352
+ try {
1353
+ const value = await (0, import_promises2.stat)(path);
1354
+ return `${value.dev}:${value.ino}`;
1355
+ } catch {
1356
+ return void 0;
1357
+ }
1358
+ }
1359
+
1239
1360
  // src/conversions.ts
1240
1361
  var WikiGraphConversionManager = class {
1241
1362
  #runtime;
@@ -1260,23 +1381,33 @@ var WikiGraphConversionManager = class {
1260
1381
  }
1261
1382
  const requiresDigest = options.input.format !== "wikg";
1262
1383
  const requiresLLM = requiresDigest && targetStage !== "planned" && targetStage !== "sourced";
1384
+ const llmJSON = resolveWikiGraphLLMJSON(options);
1385
+ const injectedLLM = llmJSON === void 0 ? getWikiGraphSDKProviders().llm : void 0;
1263
1386
  const config = await loadWikiGraphRuntimeConfig({
1264
- ...options.llmJSON === void 0 ? {} : { llmJSON: options.llmJSON }
1387
+ ...llmJSON === void 0 ? {} : { llmJSON },
1388
+ ...injectedLLM === void 0 ? {} : { skipLLMConfig: true },
1389
+ ...getWikiGraphSDKProviders().embedding === void 0 ? {} : { skipEmbeddingConfig: true }
1265
1390
  });
1266
- const app = new import_wiki_graph_core2.WikiGraph({
1391
+ const app = new import_wiki_graph_core3.WikiGraph({
1267
1392
  ...options.verbose === true ? { verbose: true } : {},
1268
- ...requiresLLM ? { llm: buildWikiGraphLLMOptions(config) } : {}
1393
+ ...requiresLLM ? {
1394
+ llm: injectedLLM === void 0 ? buildWikiGraphLLMOptions(config) : { streamProvider: injectedLLM }
1395
+ } : {}
1269
1396
  });
1270
1397
  const documentDirectory = await prepareDigestDirectory(
1271
1398
  options.digestDirectory,
1272
1399
  requiresDigest
1273
1400
  );
1274
1401
  let chapterCount;
1402
+ let chapterPaths;
1275
1403
  const write = async (archive) => {
1276
1404
  if (requiresDigest) await options.onSourceImported?.();
1277
1405
  if (typeof archive.readToc === "function") {
1278
1406
  const toc = await archive.readToc();
1279
1407
  chapterCount = toc === void 0 ? void 0 : countTocChapters(toc.items);
1408
+ if (options.output.format === "wikg") {
1409
+ chapterPaths = toc === void 0 ? [] : collectTocChapterPaths(toc.items);
1410
+ }
1280
1411
  }
1281
1412
  await writeArchive(archive, options.output.path, options.output.format);
1282
1413
  };
@@ -1285,7 +1416,9 @@ var WikiGraphConversionManager = class {
1285
1416
  throw new Error("wikg input requires a file path.");
1286
1417
  }
1287
1418
  await app.openSession(
1288
- new NodeFile(resolveWikiGraphRuntimePath(options.input.path)),
1419
+ new NodeFile(
1420
+ await assertStandaloneWikiGraphArchivePath(options.input.path)
1421
+ ),
1289
1422
  write
1290
1423
  );
1291
1424
  } else if ("stream" in options.input) {
@@ -1328,6 +1461,7 @@ var WikiGraphConversionManager = class {
1328
1461
  const sourceArtifact = await resolveSourceArtifact(options.input);
1329
1462
  return {
1330
1463
  ...chapterCount === void 0 ? {} : { chapterCount },
1464
+ ...chapterPaths === void 0 ? {} : { chapterPaths },
1331
1465
  inputFormat: options.input.format,
1332
1466
  outputFormat: options.output.format,
1333
1467
  outputPath: options.output.path,
@@ -1340,11 +1474,12 @@ async function prepareDigestDirectory(path, required) {
1340
1474
  if (!required || normalized === void 0 || normalized === "")
1341
1475
  return void 0;
1342
1476
  const resolved = resolveWikiGraphRuntimePath(normalized);
1343
- await (0, import_promises2.rm)(resolved, { force: true, recursive: true });
1477
+ await (0, import_promises3.rm)(resolved, { force: true, recursive: true });
1344
1478
  return new NodeDirectory(resolved);
1345
1479
  }
1346
1480
  async function writeArchive(archive, path, format) {
1347
- const file = new NodeFile(resolveWikiGraphRuntimePath(path));
1481
+ const outputPath = format === "wikg" ? await assertStandaloneWikiGraphArchivePath(path) : resolveWikiGraphRuntimePath(path);
1482
+ const file = new NodeFile(outputPath);
1348
1483
  if (format === "epub") await archive.exportEpub(file);
1349
1484
  else if (format === "wikg") await archive.saveAs(file);
1350
1485
  else if (format === "pcex") throw new Error("pcex output is not supported.");
@@ -1373,7 +1508,7 @@ async function resolveSourceArtifact(input) {
1373
1508
  return {
1374
1509
  digest: hash.digest("hex"),
1375
1510
  mediaType: "application/epub+zip",
1376
- name: (0, import_path3.basename)(path)
1511
+ name: (0, import_path4.basename)(path)
1377
1512
  };
1378
1513
  }
1379
1514
  function isNodeErrorCode(error, code) {
@@ -1389,6 +1524,21 @@ function countTocChapters(items) {
1389
1524
  }
1390
1525
  return count;
1391
1526
  }
1527
+ function collectTocChapterPaths(items, ancestorKeys = []) {
1528
+ const paths = [];
1529
+ for (const item of items) {
1530
+ const key = item.key ?? `chapter-${item.serialId ?? "group"}`;
1531
+ const chapterPath = [...ancestorKeys, key];
1532
+ if (item.serialId !== void 0) paths.push(chapterPath.join("/"));
1533
+ paths.push(
1534
+ ...collectTocChapterPaths(
1535
+ item.children,
1536
+ chapterPath
1537
+ )
1538
+ );
1539
+ }
1540
+ return paths;
1541
+ }
1392
1542
  // Annotate the CommonJS export names for ESM import in node:
1393
1543
  0 && (module.exports = {
1394
1544
  WikiGraphConversionManager