wiki-graph-sdk 0.9.0 → 0.9.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 (51) hide show
  1. package/dist/archives.cjs +306 -135
  2. package/dist/archives.cjs.map +1 -1
  3. package/dist/archives.js +315 -140
  4. package/dist/archives.js.map +1 -1
  5. package/dist/conversions.cjs +268 -99
  6. package/dist/conversions.cjs.map +1 -1
  7. package/dist/conversions.js +274 -103
  8. package/dist/conversions.js.map +1 -1
  9. package/dist/default-worker.cjs +258 -101
  10. package/dist/default-worker.cjs.map +1 -1
  11. package/dist/default-worker.js +264 -105
  12. package/dist/default-worker.js.map +1 -1
  13. package/dist/embedding.cjs +214 -54
  14. package/dist/embedding.cjs.map +1 -1
  15. package/dist/embedding.js +214 -54
  16. package/dist/embedding.js.map +1 -1
  17. package/dist/gc.cjs +214 -54
  18. package/dist/gc.cjs.map +1 -1
  19. package/dist/gc.js +214 -54
  20. package/dist/gc.js.map +1 -1
  21. package/dist/index.cjs +343 -165
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +357 -174
  25. package/dist/index.js.map +1 -1
  26. package/dist/local-config.cjs +214 -54
  27. package/dist/local-config.cjs.map +1 -1
  28. package/dist/local-config.js +214 -54
  29. package/dist/local-config.js.map +1 -1
  30. package/dist/maintenance.cjs +264 -97
  31. package/dist/maintenance.cjs.map +1 -1
  32. package/dist/maintenance.js +270 -101
  33. package/dist/maintenance.js.map +1 -1
  34. package/dist/node-platform.cjs +214 -54
  35. package/dist/node-platform.cjs.map +1 -1
  36. package/dist/node-platform.d.ts +2 -0
  37. package/dist/node-platform.js +214 -54
  38. package/dist/node-platform.js.map +1 -1
  39. package/dist/runtime-config.cjs +214 -54
  40. package/dist/runtime-config.cjs.map +1 -1
  41. package/dist/runtime-config.js +214 -54
  42. package/dist/runtime-config.js.map +1 -1
  43. package/dist/stage.cjs +214 -54
  44. package/dist/stage.cjs.map +1 -1
  45. package/dist/stage.js +214 -54
  46. package/dist/stage.js.map +1 -1
  47. package/dist/worker.cjs +257 -96
  48. package/dist/worker.cjs.map +1 -1
  49. package/dist/worker.js +263 -100
  50. package/dist/worker.js.map +1 -1
  51. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -11,7 +11,9 @@ import { Readable as Readable2 } from "stream";
11
11
  import {
12
12
  addChapter,
13
13
  applyChapterTree,
14
- assertArchiveIndexArtifactsReady,
14
+ assertArchiveQueryReady,
15
+ resolveIndexedArchiveChapterScope,
16
+ ensureWikiGraphArchiveSchemaCurrent,
15
17
  assertNoActiveBuildJobConflicts,
16
18
  assertNoActiveBuildJobs,
17
19
  deleteArchiveSearchSessions,
@@ -162,6 +164,15 @@ var NodeFile = class {
162
164
  this.name = name;
163
165
  }
164
166
  path;
167
+ async getPhysicalIdentity() {
168
+ const value = await fsPromises.stat(this.path).catch((error) => {
169
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
170
+ return void 0;
171
+ throw error;
172
+ });
173
+ if (value === void 0) return void 0;
174
+ return `${value.dev}:${value.ino}`;
175
+ }
165
176
  kind = "file";
166
177
  [NODE_RESOURCE_KIND] = "file";
167
178
  identity;
@@ -286,6 +297,15 @@ var NodeDirectory = class _NodeDirectory {
286
297
  this.name = pathModule.basename(path);
287
298
  }
288
299
  path;
300
+ async getPhysicalIdentity() {
301
+ const value = await fsPromises.stat(this.path).catch((error) => {
302
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
303
+ return void 0;
304
+ throw error;
305
+ });
306
+ if (value === void 0) return void 0;
307
+ return `${value.dev}:${value.ino}`;
308
+ }
289
309
  kind = "directory";
290
310
  [NODE_RESOURCE_KIND] = "directory";
291
311
  identity;
@@ -295,8 +315,10 @@ var NodeDirectory = class _NodeDirectory {
295
315
  const file = new NodeFile(pathModule.join(this.path, name));
296
316
  try {
297
317
  return (await fsPromises.stat(file.path)).isFile() ? file : void 0;
298
- } catch {
299
- return void 0;
318
+ } catch (error) {
319
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
320
+ return void 0;
321
+ throw error;
300
322
  }
301
323
  }
302
324
  async getLastModified() {
@@ -314,8 +336,10 @@ var NodeDirectory = class _NodeDirectory {
314
336
  const directory = new _NodeDirectory(pathModule.join(this.path, name));
315
337
  try {
316
338
  return (await fsPromises.stat(directory.path)).isDirectory() ? directory : void 0;
317
- } catch {
318
- return void 0;
339
+ } catch (error) {
340
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
341
+ return void 0;
342
+ throw error;
319
343
  }
320
344
  }
321
345
  async list() {
@@ -439,14 +463,23 @@ async function openNativeNodeDatabase(file, flags) {
439
463
  });
440
464
  });
441
465
  }
442
- async function openNodeZip(file) {
466
+ async function openNodeZip(file, options = {}) {
443
467
  const path = getBrandedNodeResourcePath(file, "file");
444
468
  if (path === void 0) {
445
469
  throw new TypeError("The Node ZIP adapter requires a NodeFile");
446
470
  }
447
- const zipFile = await new Promise((resolve4, reject) => {
448
- yauzl.open(
449
- path,
471
+ const handle = await fsPromises.open(path, "r");
472
+ let size;
473
+ try {
474
+ size = (await handle.stat()).size;
475
+ } catch (error) {
476
+ await handle.close();
477
+ throw error;
478
+ }
479
+ const open2 = () => new Promise((resolve4, reject) => {
480
+ yauzl.fromRandomAccessReader(
481
+ new NodeZipSource(handle),
482
+ size,
450
483
  { autoClose: false, lazyEntries: true },
451
484
  (error, opened) => {
452
485
  if (error || opened === void 0)
@@ -455,63 +488,192 @@ async function openNodeZip(file) {
455
488
  }
456
489
  );
457
490
  });
458
- const entries = await new Promise(
459
- (resolve4, reject) => {
460
- const discovered = /* @__PURE__ */ new Map();
461
- const rejectAndClose = (error) => {
462
- zipFile.close();
463
- reject(
464
- error instanceof Error ? error : new Error("Cannot scan ZIP central directory")
465
- );
466
- };
467
- const resolveEntries = () => {
468
- zipFile.off("error", rejectAndClose);
469
- resolve4(discovered);
470
- };
471
- zipFile.on("entry", (entry) => {
472
- if (!entry.fileName.endsWith("/")) {
473
- discovered.set(entry.fileName, entry);
474
- }
475
- zipFile.readEntry();
476
- });
477
- zipFile.once("error", rejectAndClose);
478
- zipFile.once("end", resolveEntries);
479
- zipFile.readEntry();
480
- }
481
- );
491
+ try {
492
+ (await open2()).close();
493
+ } catch (error) {
494
+ await handle.close();
495
+ throw error;
496
+ }
482
497
  let closed = false;
498
+ let pending = Promise.resolve();
499
+ let closing;
500
+ const run = (operation) => {
501
+ if (closed)
502
+ return Promise.reject(new Error("Cannot read a closed ZIP archive"));
503
+ const result = pending.then(async () => {
504
+ const zip = await open2();
505
+ try {
506
+ return await operation(zip);
507
+ } finally {
508
+ zip.close();
509
+ }
510
+ });
511
+ pending = result.then(
512
+ () => void 0,
513
+ () => void 0
514
+ );
515
+ return result;
516
+ };
517
+ const withEntry = (name, operation) => run(async (zip) => {
518
+ let exact;
519
+ let alias;
520
+ let aliasCollision = false;
521
+ await scanNodeZip(zip, (entry) => {
522
+ if (entry.fileName === name) exact = entry;
523
+ if (normalizeNodeZipName(entry.fileName) === name) {
524
+ if (alias !== void 0 && alias.fileName !== entry.fileName)
525
+ aliasCollision = true;
526
+ alias = entry;
527
+ }
528
+ });
529
+ if ((exact === void 0 || options.entryNameMode === "normalized") && aliasCollision) {
530
+ let bestPosition = -1;
531
+ const candidates = await open2();
532
+ try {
533
+ await scanNodeZip(candidates, async (entry) => {
534
+ if (normalizeNodeZipName(entry.fileName) !== name) return;
535
+ const probe = await open2();
536
+ let position = 0;
537
+ try {
538
+ await scanNodeZip(probe, (candidate) => {
539
+ if (candidate.fileName === entry.fileName) return false;
540
+ position++;
541
+ });
542
+ } finally {
543
+ probe.close();
544
+ }
545
+ if (position >= bestPosition) {
546
+ bestPosition = position;
547
+ alias = entry;
548
+ }
549
+ });
550
+ return await operation(candidates, alias);
551
+ } finally {
552
+ candidates.close();
553
+ }
554
+ }
555
+ return await operation(
556
+ zip,
557
+ options.entryNameMode === "normalized" ? alias : exact ?? alias
558
+ );
559
+ });
483
560
  return {
484
561
  close: () => {
485
- if (!closed) zipFile.close();
486
562
  closed = true;
487
- return Promise.resolve();
563
+ closing ??= pending.then(() => handle.close());
564
+ return closing;
488
565
  },
489
- copyEntry: async (name, target) => {
490
- if (closed) throw new Error("Cannot read a closed ZIP archive");
491
- const entry = entries.get(name);
566
+ copyEntry: (name, target) => withEntry(name, async (zip, entry) => {
492
567
  if (entry === void 0) return false;
493
- await copyNodeZipEntry(zipFile, entry, target);
568
+ await copyNodeZipEntry(zip, entry, target);
494
569
  return true;
495
- },
496
- getEntrySize: (name) => {
497
- if (closed) throw new Error("Cannot read a closed ZIP archive");
498
- return Promise.resolve(entries.get(name)?.uncompressedSize);
499
- },
500
- listEntries: () => Promise.resolve([...entries.keys()]),
501
- readEntryRange: async (name, offset, length) => {
502
- if (closed) throw new Error("Cannot read a closed ZIP archive");
503
- const entry = entries.get(name);
570
+ }),
571
+ getEntrySize: (name) => withEntry(
572
+ name,
573
+ (_zip, entry) => Promise.resolve(entry?.uncompressedSize)
574
+ ),
575
+ listEntries: () => run(async (zip) => {
576
+ const names = /* @__PURE__ */ new Set();
577
+ await scanNodeZip(zip, (entry) => {
578
+ names.add(entry.fileName);
579
+ });
580
+ return [...names];
581
+ }),
582
+ readEntryRange: (name, offset, length) => withEntry(name, async (zip, entry) => {
504
583
  if (entry === void 0) return void 0;
505
- return await readNodeZipEntryRange(zipFile, entry, offset, length);
506
- },
507
- readEntry: async (name) => {
508
- if (closed) throw new Error("Cannot read a closed ZIP archive");
509
- const entry = entries.get(name);
584
+ return await readNodeZipEntryRange(zip, entry, offset, length);
585
+ }),
586
+ readEntry: (name) => withEntry(name, async (zip, entry) => {
510
587
  if (entry === void 0) return void 0;
511
- return await readNodeZipEntry(zipFile, entry);
512
- }
588
+ return await readNodeZipEntry(zip, entry);
589
+ })
513
590
  };
514
591
  }
592
+ var NodeZipSource = class extends yauzl.RandomAccessReader {
593
+ constructor(handle) {
594
+ super();
595
+ this.handle = handle;
596
+ }
597
+ handle;
598
+ read(buffer, offset, length, position, callback) {
599
+ const read2 = (written) => {
600
+ if (written === length) {
601
+ callback(null);
602
+ return;
603
+ }
604
+ fs.read(
605
+ this.handle.fd,
606
+ buffer,
607
+ offset + written,
608
+ length - written,
609
+ position + written,
610
+ (error, bytesRead) => {
611
+ if (error) callback(error);
612
+ else if (bytesRead === 0)
613
+ callback(new Error("Unexpected end of ZIP file"));
614
+ else read2(written + bytesRead);
615
+ }
616
+ );
617
+ };
618
+ read2(0);
619
+ }
620
+ _readStreamForRange(start, end) {
621
+ const handle = this.handle;
622
+ return Readable.from(
623
+ (async function* () {
624
+ for (let position = start; position < end; ) {
625
+ const buffer = Buffer.allocUnsafe(
626
+ Math.min(64 * 1024, end - position)
627
+ );
628
+ const { bytesRead } = await handle.read(
629
+ buffer,
630
+ 0,
631
+ buffer.length,
632
+ position
633
+ );
634
+ if (bytesRead === 0) return;
635
+ position += bytesRead;
636
+ yield buffer.subarray(0, bytesRead);
637
+ }
638
+ })()
639
+ );
640
+ }
641
+ };
642
+ function normalizeNodeZipName(name) {
643
+ const normalized = name.replaceAll("\\", "/").trim().split("/").filter((part) => part !== "" && part !== ".").join("/");
644
+ return normalized.split("/").includes("..") ? void 0 : normalized;
645
+ }
646
+ async function scanNodeZip(zip, visit) {
647
+ await new Promise((resolve4, reject) => {
648
+ const cleanup = () => {
649
+ zip.off("entry", onEntry);
650
+ zip.off("end", onEnd);
651
+ zip.off("error", onError);
652
+ };
653
+ const onError = (error) => {
654
+ cleanup();
655
+ reject(error);
656
+ };
657
+ const onEnd = () => {
658
+ cleanup();
659
+ resolve4();
660
+ };
661
+ const onEntry = (entry) => {
662
+ void Promise.resolve().then(() => entry.fileName.endsWith("/") ? void 0 : visit(entry)).then((keepReading) => {
663
+ if (keepReading === false) onEnd();
664
+ else zip.readEntry();
665
+ }).catch(
666
+ (error) => onError(
667
+ error instanceof Error ? error : new Error("Cannot scan ZIP", { cause: error })
668
+ )
669
+ );
670
+ };
671
+ zip.on("entry", onEntry);
672
+ zip.once("end", onEnd);
673
+ zip.once("error", onError);
674
+ zip.readEntry();
675
+ });
676
+ }
515
677
  async function copyNodeZipEntry(zipFile, entry, target) {
516
678
  const writer = await target.openWriter();
517
679
  try {
@@ -1410,17 +1572,29 @@ function resolveWikiGraphRuntimePath(path) {
1410
1572
 
1411
1573
  // src/archive/target.ts
1412
1574
  import { realpath, stat as stat2 } from "fs/promises";
1413
- import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute3, join as join3, relative, resolve as resolve3 } from "path";
1575
+ import { basename as basename2, dirname as dirname2, join as join3, resolve as resolve3 } from "path";
1414
1576
  import {
1415
1577
  formatLocatedWikiGraphUri,
1416
1578
  formatWikiGraphLibraryUri,
1417
- listWikiGraphLibraries,
1418
- listWikiGraphLibraryArchives,
1579
+ findWikiGraphLibraryByPhysicalIdentity,
1580
+ findWikiGraphLibraryArchivePhysicalAliases,
1419
1581
  parseLocatedWikiGraphUri,
1420
1582
  parseWikiGraphLibraryUri,
1421
1583
  resolveWikiGraphLibrary,
1422
- resolveWikiGraphLibraryArchiveFile
1584
+ resolveWikiGraphLibraryArchiveFile,
1585
+ isWikiGraphSchemaVersionError,
1586
+ WikiGraphSchemaVersionError
1423
1587
  } from "wiki-graph-core";
1588
+ function rethrowArchiveSchemaError(error, target) {
1589
+ if (isWikiGraphSchemaVersionError(error) && error.target.kind === "archive") {
1590
+ throw new WikiGraphSchemaVersionError(
1591
+ target.kind === "standalone" ? { kind: "archive", path: resolveWikiGraphRuntimePath(target.path) } : { kind: "library", uri: target.uri.split("/arc/")[0] },
1592
+ error.actualVersion,
1593
+ error.supportedVersion
1594
+ );
1595
+ }
1596
+ throw error;
1597
+ }
1424
1598
  function requireWikiGraphArchiveFile(location) {
1425
1599
  return location.archiveFile;
1426
1600
  }
@@ -1441,12 +1615,7 @@ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1441
1615
  const path = resolveWikiGraphRuntimePath(inputPath);
1442
1616
  const candidate = await canonicalPath(path);
1443
1617
  const candidateIdentity = await readFileIdentity(path);
1444
- const libraries = await listWikiGraphLibraries();
1445
- const matches = await findMatchingMembers(
1446
- libraries,
1447
- candidate,
1448
- candidateIdentity
1449
- );
1618
+ const matches = await findMatchingMembers(candidate, candidateIdentity);
1450
1619
  if (matches.length > 0) {
1451
1620
  const match = requireUnambiguousManagedMatch(path, matches);
1452
1621
  throw new WikiGraphArchiveOwnershipError(
@@ -1455,15 +1624,26 @@ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1455
1624
  )}: ${path}. Use the library UUID URI ${match.archive.uri} instead.`
1456
1625
  );
1457
1626
  }
1458
- for (const library of libraries) {
1459
- const rootPath = getNodeResourcePath(library.folder);
1460
- const root = await canonicalPath(rootPath);
1461
- if (!isWithin(root, candidate)) continue;
1462
- throw new WikiGraphArchiveOwnershipError(
1463
- `Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
1464
- library.isDefault ? void 0 : library.publicId
1465
- )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1627
+ const ancestors = /* @__PURE__ */ new Set();
1628
+ for (const start of [candidate, resolve3(path)]) {
1629
+ for (let parent = dirname2(start); ; parent = dirname2(parent)) {
1630
+ ancestors.add(parent);
1631
+ if (dirname2(parent) === parent) break;
1632
+ }
1633
+ }
1634
+ for (const parent of ancestors) {
1635
+ const identity = await readFileIdentity(parent);
1636
+ const library = await findWikiGraphLibraryByPhysicalIdentity(
1637
+ identity,
1638
+ new NodeDirectory(parent).identity
1466
1639
  );
1640
+ if (library !== void 0) {
1641
+ throw new WikiGraphArchiveOwnershipError(
1642
+ `Standalone archive path belongs to registered library ${formatWikiGraphLibraryUri(
1643
+ library.isDefault ? void 0 : library.publicId
1644
+ )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1645
+ );
1646
+ }
1467
1647
  }
1468
1648
  return path;
1469
1649
  }
@@ -1481,11 +1661,7 @@ async function resolveWikiGraphArchiveTarget(file) {
1481
1661
  const path = getNodeResourcePath(file);
1482
1662
  const candidate = await canonicalPath(path);
1483
1663
  const candidateIdentity = await readFileIdentity(path);
1484
- const matches = await findMatchingMembers(
1485
- await listWikiGraphLibraries(),
1486
- candidate,
1487
- candidateIdentity
1488
- );
1664
+ const matches = await findMatchingMembers(candidate, candidateIdentity);
1489
1665
  if (matches.length > 0) {
1490
1666
  const match = requireUnambiguousManagedMatch(path, matches);
1491
1667
  return { kind: "library", uri: match.archive.uri };
@@ -1551,48 +1727,35 @@ function withObjectUri(archiveLocator, objectUri) {
1551
1727
  async function canonicalPath(path) {
1552
1728
  try {
1553
1729
  return await realpath(path);
1554
- } catch {
1730
+ } catch (error) {
1731
+ if (!(typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")))
1732
+ throw error;
1555
1733
  const absolute = resolve3(path);
1556
1734
  const parent = dirname2(absolute);
1557
1735
  return parent === absolute ? absolute : join3(await canonicalPath(parent), basename2(absolute));
1558
1736
  }
1559
1737
  }
1560
- function isWithin(root, candidate) {
1561
- const child = relative(root, candidate);
1562
- return child === "" || !child.startsWith("..") && !isAbsolute3(child);
1563
- }
1564
- async function findMatchingMembers(libraries, candidate, candidateIdentity) {
1738
+ async function findMatchingMembers(candidate, candidateIdentity) {
1739
+ if (candidateIdentity === void 0) return [];
1740
+ const archives = await findWikiGraphLibraryArchivePhysicalAliases(candidateIdentity);
1565
1741
  const members = [];
1566
- for (const library of libraries) {
1567
- const archives = await listWikiGraphLibraryArchives({
1568
- isDefault: library.isDefault,
1569
- kind: "scope",
1570
- ...library.isDefault ? {} : { publicId: library.publicId }
1571
- });
1572
- for (const archive of archives) {
1573
- const physical = archive.file ?? archive.directory;
1574
- if (physical === void 0) continue;
1742
+ for (const archive of archives) {
1743
+ const parsed = parseWikiGraphLibraryUri(archive.libraryUri);
1744
+ const library = await resolveWikiGraphLibrary(parsed);
1745
+ const physical = archive.file ?? archive.directory;
1746
+ if (library !== void 0 && physical !== void 0)
1575
1747
  members.push({
1576
1748
  archive,
1577
1749
  library,
1578
1750
  memberPath: getNodeResourcePath(physical)
1579
1751
  });
1580
- }
1581
1752
  }
1582
1753
  const exact = [];
1583
1754
  for (const member of members) {
1584
- if (await canonicalPath(member.memberPath) === candidate) {
1755
+ if (await canonicalPath(member.memberPath) === candidate)
1585
1756
  exact.push(member);
1586
- }
1587
1757
  }
1588
- if (exact.length > 0 || candidateIdentity === void 0) return exact;
1589
- const identityMatches = [];
1590
- for (const member of members) {
1591
- if (await readFileIdentity(member.memberPath) === candidateIdentity) {
1592
- identityMatches.push(member);
1593
- }
1594
- }
1595
- return identityMatches;
1758
+ return exact.length > 0 ? exact : members;
1596
1759
  }
1597
1760
  function requireUnambiguousManagedMatch(path, matches) {
1598
1761
  if (matches.length === 1) return matches[0];
@@ -1604,8 +1767,10 @@ async function readFileIdentity(path) {
1604
1767
  try {
1605
1768
  const value = await stat2(path);
1606
1769
  return `${value.dev}:${value.ino}`;
1607
- } catch {
1608
- return void 0;
1770
+ } catch (error) {
1771
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
1772
+ return void 0;
1773
+ throw error;
1609
1774
  }
1610
1775
  }
1611
1776
 
@@ -1667,11 +1832,15 @@ var WikiGraphConversionManager = class {
1667
1832
  if (!("path" in options.input)) {
1668
1833
  throw new Error("wikg input requires a file path.");
1669
1834
  }
1835
+ const inputPath = options.input.path;
1670
1836
  await app.openSession(
1671
- new NodeFile(
1672
- await assertStandaloneWikiGraphArchivePath(options.input.path)
1673
- ),
1837
+ new NodeFile(await assertStandaloneWikiGraphArchivePath(inputPath)),
1674
1838
  write
1839
+ ).catch(
1840
+ (error) => rethrowArchiveSchemaError(error, {
1841
+ kind: "standalone",
1842
+ path: inputPath
1843
+ })
1675
1844
  );
1676
1845
  } else if ("stream" in options.input) {
1677
1846
  await app.digestTextStreamSession(
@@ -2096,6 +2265,12 @@ import {
2096
2265
  async function writeWikiGraphArchiveLocation(location, operation, options = {}) {
2097
2266
  const cacheOnly = options.searchIndexWritebackPolicy === "cache";
2098
2267
  const write = async (archiveFile = location.archiveFile) => {
2268
+ if (cacheOnly) {
2269
+ return await new WikiGraphArchiveFile(archiveFile).readDocument(
2270
+ operation,
2271
+ { searchIndexWritebackPolicy: "cache" }
2272
+ );
2273
+ }
2099
2274
  const writeOptions = {
2100
2275
  ...cacheOnly ? {} : { derivedStateKeys: [location.archiveKey, location.archivePath] },
2101
2276
  ...options.invalidateContinuationCursors === void 0 ? {} : {
@@ -2471,10 +2646,15 @@ var WikiGraphArchiveManager = class {
2471
2646
  }, options.signal);
2472
2647
  }
2473
2648
  async open(target, options = {}) {
2474
- const location = await this.#runtime.run(
2475
- async () => await resolveWikiGraphArchiveLocation(target),
2476
- options.signal
2477
- );
2649
+ const location = await this.#runtime.run(async () => {
2650
+ const location2 = await resolveWikiGraphArchiveLocation(target);
2651
+ try {
2652
+ await ensureWikiGraphArchiveSchemaCurrent(location2.archiveFile);
2653
+ } catch (error) {
2654
+ rethrowArchiveSchemaError(error, target);
2655
+ }
2656
+ return location2;
2657
+ }, options.signal);
2478
2658
  return new WikiGraphArchiveHandle(this.#runtime, location);
2479
2659
  }
2480
2660
  };
@@ -2525,15 +2705,11 @@ var WikiGraphArchiveHandle = class {
2525
2705
  options.queryMode,
2526
2706
  options.signal
2527
2707
  );
2528
- const result = await this.#writeDocument(
2708
+ const result = await this.#readDocument(
2529
2709
  async (document) => {
2530
2710
  const chapters = await this.#resolveQueryChapters(document, options, {
2531
2711
  embeddingProvider
2532
2712
  });
2533
- await ensureArchiveSearchIndex(document, {
2534
- ...chapters === void 0 ? {} : { chapters },
2535
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2536
- });
2537
2713
  return await findArchiveObjects(document, query, {
2538
2714
  ...withoutOperationAndScope(options),
2539
2715
  archiveKey: this.archiveKey,
@@ -2542,7 +2718,6 @@ var WikiGraphArchiveHandle = class {
2542
2718
  });
2543
2719
  },
2544
2720
  {
2545
- searchIndexWritebackPolicy: "cache",
2546
2721
  ...options.signal === void 0 ? {} : { signal: options.signal }
2547
2722
  }
2548
2723
  );
@@ -2647,6 +2822,7 @@ var WikiGraphArchiveHandle = class {
2647
2822
  async (document) => {
2648
2823
  const chapters = await this.#resolveScope(document, options);
2649
2824
  await ensureArchiveSearchIndex(document, {
2825
+ rebuild: true,
2650
2826
  ...chapters === void 0 ? {} : { chapters },
2651
2827
  ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2652
2828
  });
@@ -2936,15 +3112,11 @@ var WikiGraphArchiveHandle = class {
2936
3112
  options.queryMode,
2937
3113
  options.signal
2938
3114
  );
2939
- const result = await this.#writeDocument(
3115
+ const result = await this.#readDocument(
2940
3116
  async (document) => {
2941
3117
  const chapters = await this.#resolveQueryChapters(document, options, {
2942
3118
  embeddingProvider
2943
3119
  });
2944
- await ensureArchiveSearchIndex(document, {
2945
- ...chapters === void 0 ? {} : { chapters },
2946
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2947
- });
2948
3120
  return await listRelatedArchiveObjects(document, objectUri, {
2949
3121
  ...withoutOperation(options),
2950
3122
  ...embeddingProvider === void 0 ? {} : { embeddingProvider },
@@ -2952,7 +3124,6 @@ var WikiGraphArchiveHandle = class {
2952
3124
  });
2953
3125
  },
2954
3126
  {
2955
- searchIndexWritebackPolicy: "cache",
2956
3127
  ...options.signal === void 0 ? {} : { signal: options.signal }
2957
3128
  }
2958
3129
  );
@@ -2996,15 +3167,11 @@ var WikiGraphArchiveHandle = class {
2996
3167
  options.queryMode,
2997
3168
  options.signal
2998
3169
  );
2999
- const result = await this.#writeDocument(
3170
+ const result = await this.#readDocument(
3000
3171
  async (document) => {
3001
3172
  const chapters = await this.#resolveQueryChapters(document, options, {
3002
3173
  embeddingProvider
3003
3174
  });
3004
- await ensureArchiveSearchIndex(document, {
3005
- ...chapters === void 0 ? {} : { chapters },
3006
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
3007
- });
3008
3175
  return await listArchiveEvidence(document, objectUri, {
3009
3176
  ...withoutOperation(options),
3010
3177
  ...embeddingProvider === void 0 ? {} : { embeddingProvider },
@@ -3012,7 +3179,6 @@ var WikiGraphArchiveHandle = class {
3012
3179
  });
3013
3180
  },
3014
3181
  {
3015
- searchIndexWritebackPolicy: "cache",
3016
3182
  ...options.signal === void 0 ? {} : { signal: options.signal }
3017
3183
  }
3018
3184
  );
@@ -3129,6 +3295,8 @@ var WikiGraphArchiveHandle = class {
3129
3295
  this.#location.archiveFile
3130
3296
  ).readDocument(operation),
3131
3297
  options.signal
3298
+ ).catch(
3299
+ (error) => rethrowArchiveSchemaError(error, this.#location.target)
3132
3300
  );
3133
3301
  }
3134
3302
  async #writeDocument(operation, options = {}) {
@@ -3140,33 +3308,32 @@ var WikiGraphArchiveHandle = class {
3140
3308
  searchIndexWritebackPolicy: options.searchIndexWritebackPolicy
3141
3309
  }
3142
3310
  });
3143
- }, options.signal);
3311
+ }, options.signal).catch(
3312
+ (error) => rethrowArchiveSchemaError(error, this.#location.target)
3313
+ );
3144
3314
  }
3145
3315
  async #resolveScope(document, options) {
3146
3316
  if (options.chapters !== void 0) return options.chapters;
3147
3317
  return (await resolveArchiveScope(document, this.objectUri, options.depth))?.chapterIds;
3148
3318
  }
3149
3319
  async #resolveQueryChapters(document, options, capabilities) {
3150
- const chapters = await this.#resolveScope(document, options);
3320
+ const parsed = parseChapterScopePath(this.objectUri);
3321
+ const chapters = options.chapters ?? (parsed === void 0 || parsed.kind === "collection" && options.depth === void 0 ? void 0 : await resolveIndexedArchiveChapterScope(
3322
+ document,
3323
+ parsed.kind === "chapter" ? parsed.chapterPath : void 0,
3324
+ options.depth
3325
+ ));
3151
3326
  const coverageOptions = {
3152
3327
  ...chapters === void 0 ? {} : { chapters },
3153
3328
  ...capabilities.embeddingProvider === void 0 ? {} : { embeddingProvider: capabilities.embeddingProvider },
3154
3329
  requireEmbeddingProvider: true,
3155
3330
  ...options.queryMode === void 0 ? {} : { queryMode: options.queryMode }
3156
3331
  };
3157
- if (options.skipUnindexed !== true) {
3158
- await assertArchiveIndexArtifactsReady(document, coverageOptions);
3159
- return chapters;
3160
- }
3161
- const queryable = await listArchiveQueryableChapterIds(document, {
3162
- ...coverageOptions
3332
+ await assertArchiveQueryReady(document, {
3333
+ ...coverageOptions,
3334
+ ...options.skipUnindexed === void 0 ? {} : { skipUnindexed: options.skipUnindexed }
3163
3335
  });
3164
- if (queryable.length === 0) {
3165
- throw new Error(
3166
- "Wiki Graph query is not ready. No chapters in this scope have a current FTS artifact or source embedding artifact."
3167
- );
3168
- }
3169
- return queryable;
3336
+ return chapters;
3170
3337
  }
3171
3338
  async #resolveQueryEmbeddingProvider(queryMode, signal) {
3172
3339
  if (queryMode === "fts") return void 0;
@@ -3185,6 +3352,10 @@ var WikiGraphArchiveHandle = class {
3185
3352
  async function ensureArchiveSearchIndex(document, options = {}) {
3186
3353
  const scope = options.chapters === void 0 ? {} : { chapters: options.chapters };
3187
3354
  if (await isArchiveSearchIndexCurrent2(document, scope)) return;
3355
+ if (options.rebuild !== true)
3356
+ throw new Error(
3357
+ "Archive search index is missing or dirty. Run `wg <archive-uri>/index sync` explicitly before querying."
3358
+ );
3188
3359
  await rebuildArchiveSearchIndex(document, void 0, {
3189
3360
  ...scope,
3190
3361
  ...options.embeddingProvider === void 0 ? {} : { embeddingProvider: options.embeddingProvider }
@@ -3581,7 +3752,7 @@ async function continueArchiveCursor(cursor, limit) {
3581
3752
  const location = await resolveWikiGraphArchiveLocation(
3582
3753
  archiveTargetFromLogicalLocator(getCursorArchivePath(cursor))
3583
3754
  );
3584
- const read = async (document) => {
3755
+ const read2 = async (document) => {
3585
3756
  switch (cursor.kind) {
3586
3757
  case "source-locators":
3587
3758
  return await listArchiveSourceLocators2(document, cursor.targetUri, {
@@ -3627,7 +3798,9 @@ async function continueArchiveCursor(cursor, limit) {
3627
3798
  });
3628
3799
  }
3629
3800
  };
3630
- return location.archiveFile.kind === "directory" ? await new WikiGraphDirectoryFile3(location.archiveFile).readDocument(read) : await new WikiGraphArchiveFile3(location.archiveFile).readDocument(read);
3801
+ return await (location.archiveFile.kind === "directory" ? new WikiGraphDirectoryFile3(location.archiveFile).readDocument(read2) : new WikiGraphArchiveFile3(location.archiveFile).readDocument(read2)).catch(
3802
+ (error) => rethrowArchiveSchemaError(error, location.target)
3803
+ );
3631
3804
  }
3632
3805
  async function continueLibraryCursor(cursor, limit) {
3633
3806
  const embeddingProvider = cursor.kind === "evidence" || cursor.kind === "related" ? await resolveCursorEmbeddingProvider(cursor) : void 0;
@@ -5022,6 +5195,7 @@ function forwardAbort(source, target) {
5022
5195
  // src/libraries.ts
5023
5196
  import {
5024
5197
  addWikiGraphLibraryArchive,
5198
+ ensureWikiGraphArchiveSchemaCurrent as ensureWikiGraphArchiveSchemaCurrent2,
5025
5199
  assertWikiGraphLibrarySchemaCurrent,
5026
5200
  cleanWikiGraphLibraryIndex,
5027
5201
  clearWikiGraphLibraryMetadata,
@@ -5035,8 +5209,8 @@ import {
5035
5209
  getWikiGraphLibraryArchive,
5036
5210
  getWikiGraphLibraryMetadata,
5037
5211
  listRelatedWikiGraphLibraryObjects as listRelatedWikiGraphLibraryObjects2,
5038
- listWikiGraphLibraries as listWikiGraphLibraries2,
5039
- listWikiGraphLibraryArchives as listWikiGraphLibraryArchives2,
5212
+ listWikiGraphLibraries,
5213
+ listWikiGraphLibraryArchives,
5040
5214
  listWikiGraphLibraryArchiveMembers as listWikiGraphLibraryArchiveMembers2,
5041
5215
  listWikiGraphLibraryEvidence as listWikiGraphLibraryEvidence2,
5042
5216
  listWikiGraphLibraryObjects as listWikiGraphLibraryObjects2,
@@ -5150,20 +5324,27 @@ var WikiGraphLibraryManager = class {
5150
5324
  throwIfAborted(options.signal);
5151
5325
  const archive = await getWikiGraphLibraryArchive(parsedTarget);
5152
5326
  const source = requireReadableLibraryArchiveFile(archive);
5327
+ await ensureWikiGraphArchiveSchemaCurrent2(source).catch(
5328
+ (error) => rethrowArchiveSchemaError(error, {
5329
+ kind: "library",
5330
+ uri: archive.uri
5331
+ })
5332
+ );
5153
5333
  let temporaryDirectory;
5154
- const file = source.kind === "directory" ? await (async () => {
5155
- temporaryDirectory = await mkdtemp2(
5156
- join5(tmpdir2(), "wikigraph-library-read-")
5157
- );
5158
- const output = new NodeFile(
5159
- join5(temporaryDirectory, "archive.wikg")
5160
- );
5161
- await writeWikgArchive2(source, output);
5162
- return output;
5163
- })() : source;
5164
- const reader = await file.openReader();
5334
+ let reader;
5165
5335
  let active = true;
5166
5336
  try {
5337
+ const file = source.kind === "directory" ? await (async () => {
5338
+ temporaryDirectory = await mkdtemp2(
5339
+ join5(tmpdir2(), "wikigraph-library-read-")
5340
+ );
5341
+ const output = new NodeFile(
5342
+ join5(temporaryDirectory, "archive.wikg")
5343
+ );
5344
+ await writeWikgArchive2(source, output);
5345
+ return output;
5346
+ })() : source;
5347
+ reader = await file.openReader();
5167
5348
  const content = {
5168
5349
  mediaType: "application/vnd.wiki-graph.archive",
5169
5350
  size: reader.size,
@@ -5180,9 +5361,12 @@ var WikiGraphLibraryManager = class {
5180
5361
  );
5181
5362
  } finally {
5182
5363
  active = false;
5183
- await reader.close();
5184
- if (temporaryDirectory !== void 0)
5185
- await rm4(temporaryDirectory, { force: true, recursive: true });
5364
+ try {
5365
+ await reader?.close();
5366
+ } finally {
5367
+ if (temporaryDirectory !== void 0)
5368
+ await rm4(temporaryDirectory, { force: true, recursive: true });
5369
+ }
5186
5370
  }
5187
5371
  },
5188
5372
  options.signal === void 0 ? {} : { signal: options.signal }
@@ -5492,7 +5676,7 @@ var WikiGraphLibraryManager = class {
5492
5676
  }
5493
5677
  async list() {
5494
5678
  const records = await this.#runtime.run(
5495
- async () => await listWikiGraphLibraries2()
5679
+ async () => await listWikiGraphLibraries()
5496
5680
  );
5497
5681
  return records.map((record) => new WikiGraphLibrary(this.#runtime, record));
5498
5682
  }
@@ -5515,7 +5699,7 @@ var WikiGraphLibrary = class {
5515
5699
  async archives() {
5516
5700
  const target = requireLibraryTarget(this.uri);
5517
5701
  return (await this.#runtime.run(
5518
- async () => await listWikiGraphLibraryArchives2(target)
5702
+ async () => await listWikiGraphLibraryArchives(target)
5519
5703
  )).map(toArchiveSnapshot);
5520
5704
  }
5521
5705
  async scan() {
@@ -5687,7 +5871,9 @@ var WikiGraphMaintenanceManager = class {
5687
5871
  return await upgradeWikiGraphMaintenanceTarget({
5688
5872
  file: new NodeFile(path),
5689
5873
  kind: "archive"
5690
- });
5874
+ }).catch(
5875
+ (error) => rethrowArchiveSchemaError(error, { kind: "standalone", path })
5876
+ );
5691
5877
  },
5692
5878
  void 0,
5693
5879
  { skipHomeBootstrap: target.kind === "home" }
@@ -5716,7 +5902,6 @@ function defaultWikgOutputPath(inputPath) {
5716
5902
  import { ensureWikiGraphHomeSchemaCurrent } from "wiki-graph-core";
5717
5903
  var WikiGraphSDK = class {
5718
5904
  #context;
5719
- #homeReady;
5720
5905
  archives;
5721
5906
  conversions;
5722
5907
  config;
@@ -5747,13 +5932,7 @@ var WikiGraphSDK = class {
5747
5932
  throwIfAborted2(signal);
5748
5933
  const runWithContext = async () => await withWikiGraphSDKRuntimeContext(this.#context, async () => {
5749
5934
  if (options.skipHomeBootstrap !== true) {
5750
- this.#homeReady ??= ensureWikiGraphHomeSchemaCurrent().catch(
5751
- (error) => {
5752
- this.#homeReady = void 0;
5753
- throw error;
5754
- }
5755
- );
5756
- await this.#homeReady;
5935
+ await ensureWikiGraphHomeSchemaCurrent();
5757
5936
  }
5758
5937
  return await operation();
5759
5938
  });
@@ -5784,6 +5963,8 @@ import {
5784
5963
  LLMPaymentRequiredError,
5785
5964
  WIKI_GRAPH_URI_PREFIX,
5786
5965
  WikiGraphError,
5966
+ WikiGraphSchemaVersionError as WikiGraphSchemaVersionError2,
5967
+ isWikiGraphSchemaVersionError as isWikiGraphSchemaVersionError2,
5787
5968
  formatError as formatError3,
5788
5969
  formatLocatedChapterResourceUri,
5789
5970
  formatLocatedChapterSourceCollectionUri,
@@ -5840,6 +6021,7 @@ export {
5840
6021
  WikiGraphLibraryManager,
5841
6022
  WikiGraphMaintenanceManager,
5842
6023
  WikiGraphSDK,
6024
+ WikiGraphSchemaVersionError2 as WikiGraphSchemaVersionError,
5843
6025
  buildSearchIndexEmbeddingProvider,
5844
6026
  buildWikiGraphLLMOptions,
5845
6027
  clearLocalConfigSection,
@@ -5882,6 +6064,7 @@ export {
5882
6064
  isSourceLocatorScopeUri2 as isSourceLocatorScopeUri,
5883
6065
  isWikiGraphJobUri,
5884
6066
  isWikiGraphLibraryUri,
6067
+ isWikiGraphSchemaVersionError2 as isWikiGraphSchemaVersionError,
5885
6068
  isWikiGraphUri,
5886
6069
  iterateItems,
5887
6070
  iteratePages,