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/archives.cjs CHANGED
@@ -151,6 +151,15 @@ var NodeFile = class {
151
151
  this.name = name;
152
152
  }
153
153
  path;
154
+ async getPhysicalIdentity() {
155
+ const value = await fsPromises.stat(this.path).catch((error) => {
156
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
157
+ return void 0;
158
+ throw error;
159
+ });
160
+ if (value === void 0) return void 0;
161
+ return `${value.dev}:${value.ino}`;
162
+ }
154
163
  kind = "file";
155
164
  [NODE_RESOURCE_KIND] = "file";
156
165
  identity;
@@ -275,6 +284,15 @@ var NodeDirectory = class _NodeDirectory {
275
284
  this.name = pathModule.basename(path);
276
285
  }
277
286
  path;
287
+ async getPhysicalIdentity() {
288
+ const value = await fsPromises.stat(this.path).catch((error) => {
289
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
290
+ return void 0;
291
+ throw error;
292
+ });
293
+ if (value === void 0) return void 0;
294
+ return `${value.dev}:${value.ino}`;
295
+ }
278
296
  kind = "directory";
279
297
  [NODE_RESOURCE_KIND] = "directory";
280
298
  identity;
@@ -284,8 +302,10 @@ var NodeDirectory = class _NodeDirectory {
284
302
  const file = new NodeFile(pathModule.join(this.path, name));
285
303
  try {
286
304
  return (await fsPromises.stat(file.path)).isFile() ? file : void 0;
287
- } catch {
288
- return void 0;
305
+ } catch (error) {
306
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
307
+ return void 0;
308
+ throw error;
289
309
  }
290
310
  }
291
311
  async getLastModified() {
@@ -303,8 +323,10 @@ var NodeDirectory = class _NodeDirectory {
303
323
  const directory = new _NodeDirectory(pathModule.join(this.path, name));
304
324
  try {
305
325
  return (await fsPromises.stat(directory.path)).isDirectory() ? directory : void 0;
306
- } catch {
307
- return void 0;
326
+ } catch (error) {
327
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
328
+ return void 0;
329
+ throw error;
308
330
  }
309
331
  }
310
332
  async list() {
@@ -428,14 +450,23 @@ async function openNativeNodeDatabase(file, flags) {
428
450
  });
429
451
  });
430
452
  }
431
- async function openNodeZip(file) {
453
+ async function openNodeZip(file, options = {}) {
432
454
  const path = getBrandedNodeResourcePath(file, "file");
433
455
  if (path === void 0) {
434
456
  throw new TypeError("The Node ZIP adapter requires a NodeFile");
435
457
  }
436
- const zipFile = await new Promise((resolve4, reject) => {
437
- yauzl.open(
438
- path,
458
+ const handle = await fsPromises.open(path, "r");
459
+ let size;
460
+ try {
461
+ size = (await handle.stat()).size;
462
+ } catch (error) {
463
+ await handle.close();
464
+ throw error;
465
+ }
466
+ const open2 = () => new Promise((resolve4, reject) => {
467
+ yauzl.fromRandomAccessReader(
468
+ new NodeZipSource(handle),
469
+ size,
439
470
  { autoClose: false, lazyEntries: true },
440
471
  (error, opened) => {
441
472
  if (error || opened === void 0)
@@ -444,63 +475,192 @@ async function openNodeZip(file) {
444
475
  }
445
476
  );
446
477
  });
447
- const entries = await new Promise(
448
- (resolve4, reject) => {
449
- const discovered = /* @__PURE__ */ new Map();
450
- const rejectAndClose = (error) => {
451
- zipFile.close();
452
- reject(
453
- error instanceof Error ? error : new Error("Cannot scan ZIP central directory")
454
- );
455
- };
456
- const resolveEntries = () => {
457
- zipFile.off("error", rejectAndClose);
458
- resolve4(discovered);
459
- };
460
- zipFile.on("entry", (entry) => {
461
- if (!entry.fileName.endsWith("/")) {
462
- discovered.set(entry.fileName, entry);
463
- }
464
- zipFile.readEntry();
465
- });
466
- zipFile.once("error", rejectAndClose);
467
- zipFile.once("end", resolveEntries);
468
- zipFile.readEntry();
469
- }
470
- );
478
+ try {
479
+ (await open2()).close();
480
+ } catch (error) {
481
+ await handle.close();
482
+ throw error;
483
+ }
471
484
  let closed = false;
485
+ let pending = Promise.resolve();
486
+ let closing;
487
+ const run = (operation) => {
488
+ if (closed)
489
+ return Promise.reject(new Error("Cannot read a closed ZIP archive"));
490
+ const result = pending.then(async () => {
491
+ const zip = await open2();
492
+ try {
493
+ return await operation(zip);
494
+ } finally {
495
+ zip.close();
496
+ }
497
+ });
498
+ pending = result.then(
499
+ () => void 0,
500
+ () => void 0
501
+ );
502
+ return result;
503
+ };
504
+ const withEntry = (name, operation) => run(async (zip) => {
505
+ let exact;
506
+ let alias;
507
+ let aliasCollision = false;
508
+ await scanNodeZip(zip, (entry) => {
509
+ if (entry.fileName === name) exact = entry;
510
+ if (normalizeNodeZipName(entry.fileName) === name) {
511
+ if (alias !== void 0 && alias.fileName !== entry.fileName)
512
+ aliasCollision = true;
513
+ alias = entry;
514
+ }
515
+ });
516
+ if ((exact === void 0 || options.entryNameMode === "normalized") && aliasCollision) {
517
+ let bestPosition = -1;
518
+ const candidates = await open2();
519
+ try {
520
+ await scanNodeZip(candidates, async (entry) => {
521
+ if (normalizeNodeZipName(entry.fileName) !== name) return;
522
+ const probe = await open2();
523
+ let position = 0;
524
+ try {
525
+ await scanNodeZip(probe, (candidate) => {
526
+ if (candidate.fileName === entry.fileName) return false;
527
+ position++;
528
+ });
529
+ } finally {
530
+ probe.close();
531
+ }
532
+ if (position >= bestPosition) {
533
+ bestPosition = position;
534
+ alias = entry;
535
+ }
536
+ });
537
+ return await operation(candidates, alias);
538
+ } finally {
539
+ candidates.close();
540
+ }
541
+ }
542
+ return await operation(
543
+ zip,
544
+ options.entryNameMode === "normalized" ? alias : exact ?? alias
545
+ );
546
+ });
472
547
  return {
473
548
  close: () => {
474
- if (!closed) zipFile.close();
475
549
  closed = true;
476
- return Promise.resolve();
550
+ closing ??= pending.then(() => handle.close());
551
+ return closing;
477
552
  },
478
- copyEntry: async (name, target) => {
479
- if (closed) throw new Error("Cannot read a closed ZIP archive");
480
- const entry = entries.get(name);
553
+ copyEntry: (name, target) => withEntry(name, async (zip, entry) => {
481
554
  if (entry === void 0) return false;
482
- await copyNodeZipEntry(zipFile, entry, target);
555
+ await copyNodeZipEntry(zip, entry, target);
483
556
  return true;
484
- },
485
- getEntrySize: (name) => {
486
- if (closed) throw new Error("Cannot read a closed ZIP archive");
487
- return Promise.resolve(entries.get(name)?.uncompressedSize);
488
- },
489
- listEntries: () => Promise.resolve([...entries.keys()]),
490
- readEntryRange: async (name, offset, length) => {
491
- if (closed) throw new Error("Cannot read a closed ZIP archive");
492
- const entry = entries.get(name);
557
+ }),
558
+ getEntrySize: (name) => withEntry(
559
+ name,
560
+ (_zip, entry) => Promise.resolve(entry?.uncompressedSize)
561
+ ),
562
+ listEntries: () => run(async (zip) => {
563
+ const names = /* @__PURE__ */ new Set();
564
+ await scanNodeZip(zip, (entry) => {
565
+ names.add(entry.fileName);
566
+ });
567
+ return [...names];
568
+ }),
569
+ readEntryRange: (name, offset, length) => withEntry(name, async (zip, entry) => {
493
570
  if (entry === void 0) return void 0;
494
- return await readNodeZipEntryRange(zipFile, entry, offset, length);
495
- },
496
- readEntry: async (name) => {
497
- if (closed) throw new Error("Cannot read a closed ZIP archive");
498
- const entry = entries.get(name);
571
+ return await readNodeZipEntryRange(zip, entry, offset, length);
572
+ }),
573
+ readEntry: (name) => withEntry(name, async (zip, entry) => {
499
574
  if (entry === void 0) return void 0;
500
- return await readNodeZipEntry(zipFile, entry);
501
- }
575
+ return await readNodeZipEntry(zip, entry);
576
+ })
502
577
  };
503
578
  }
579
+ var NodeZipSource = class extends yauzl.RandomAccessReader {
580
+ constructor(handle) {
581
+ super();
582
+ this.handle = handle;
583
+ }
584
+ handle;
585
+ read(buffer, offset, length, position, callback) {
586
+ const read2 = (written) => {
587
+ if (written === length) {
588
+ callback(null);
589
+ return;
590
+ }
591
+ fs.read(
592
+ this.handle.fd,
593
+ buffer,
594
+ offset + written,
595
+ length - written,
596
+ position + written,
597
+ (error, bytesRead) => {
598
+ if (error) callback(error);
599
+ else if (bytesRead === 0)
600
+ callback(new Error("Unexpected end of ZIP file"));
601
+ else read2(written + bytesRead);
602
+ }
603
+ );
604
+ };
605
+ read2(0);
606
+ }
607
+ _readStreamForRange(start, end) {
608
+ const handle = this.handle;
609
+ return import_node_stream.Readable.from(
610
+ (async function* () {
611
+ for (let position = start; position < end; ) {
612
+ const buffer = Buffer.allocUnsafe(
613
+ Math.min(64 * 1024, end - position)
614
+ );
615
+ const { bytesRead } = await handle.read(
616
+ buffer,
617
+ 0,
618
+ buffer.length,
619
+ position
620
+ );
621
+ if (bytesRead === 0) return;
622
+ position += bytesRead;
623
+ yield buffer.subarray(0, bytesRead);
624
+ }
625
+ })()
626
+ );
627
+ }
628
+ };
629
+ function normalizeNodeZipName(name) {
630
+ const normalized = name.replaceAll("\\", "/").trim().split("/").filter((part) => part !== "" && part !== ".").join("/");
631
+ return normalized.split("/").includes("..") ? void 0 : normalized;
632
+ }
633
+ async function scanNodeZip(zip, visit) {
634
+ await new Promise((resolve4, reject) => {
635
+ const cleanup = () => {
636
+ zip.off("entry", onEntry);
637
+ zip.off("end", onEnd);
638
+ zip.off("error", onError);
639
+ };
640
+ const onError = (error) => {
641
+ cleanup();
642
+ reject(error);
643
+ };
644
+ const onEnd = () => {
645
+ cleanup();
646
+ resolve4();
647
+ };
648
+ const onEntry = (entry) => {
649
+ void Promise.resolve().then(() => entry.fileName.endsWith("/") ? void 0 : visit(entry)).then((keepReading) => {
650
+ if (keepReading === false) onEnd();
651
+ else zip.readEntry();
652
+ }).catch(
653
+ (error) => onError(
654
+ error instanceof Error ? error : new Error("Cannot scan ZIP", { cause: error })
655
+ )
656
+ );
657
+ };
658
+ zip.on("entry", onEntry);
659
+ zip.once("end", onEnd);
660
+ zip.once("error", onError);
661
+ zip.readEntry();
662
+ });
663
+ }
504
664
  async function copyNodeZipEntry(zipFile, entry, target) {
505
665
  const writer = await target.openWriter();
506
666
  try {
@@ -1273,6 +1433,16 @@ function resolveWikiGraphRuntimePath(path) {
1273
1433
  var import_promises3 = require("fs/promises");
1274
1434
  var import_path3 = require("path");
1275
1435
  var import_wiki_graph_core2 = require("wiki-graph-core");
1436
+ function rethrowArchiveSchemaError(error, target) {
1437
+ if ((0, import_wiki_graph_core2.isWikiGraphSchemaVersionError)(error) && error.target.kind === "archive") {
1438
+ throw new import_wiki_graph_core2.WikiGraphSchemaVersionError(
1439
+ target.kind === "standalone" ? { kind: "archive", path: resolveWikiGraphRuntimePath(target.path) } : { kind: "library", uri: target.uri.split("/arc/")[0] },
1440
+ error.actualVersion,
1441
+ error.supportedVersion
1442
+ );
1443
+ }
1444
+ throw error;
1445
+ }
1276
1446
  function requireWikiGraphArchiveFile(location) {
1277
1447
  return location.archiveFile;
1278
1448
  }
@@ -1293,12 +1463,7 @@ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1293
1463
  const path = resolveWikiGraphRuntimePath(inputPath);
1294
1464
  const candidate = await canonicalPath(path);
1295
1465
  const candidateIdentity = await readFileIdentity(path);
1296
- const libraries = await (0, import_wiki_graph_core2.listWikiGraphLibraries)();
1297
- const matches = await findMatchingMembers(
1298
- libraries,
1299
- candidate,
1300
- candidateIdentity
1301
- );
1466
+ const matches = await findMatchingMembers(candidate, candidateIdentity);
1302
1467
  if (matches.length > 0) {
1303
1468
  const match = requireUnambiguousManagedMatch(path, matches);
1304
1469
  throw new WikiGraphArchiveOwnershipError(
@@ -1307,15 +1472,26 @@ async function assertStandaloneWikiGraphArchivePath(inputPath) {
1307
1472
  )}: ${path}. Use the library UUID URI ${match.archive.uri} instead.`
1308
1473
  );
1309
1474
  }
1310
- for (const library of libraries) {
1311
- const rootPath = getNodeResourcePath(library.folder);
1312
- const root = await canonicalPath(rootPath);
1313
- if (!isWithin(root, candidate)) continue;
1314
- throw new WikiGraphArchiveOwnershipError(
1315
- `Standalone archive path belongs to registered library ${(0, import_wiki_graph_core2.formatWikiGraphLibraryUri)(
1316
- library.isDefault ? void 0 : library.publicId
1317
- )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1475
+ const ancestors = /* @__PURE__ */ new Set();
1476
+ for (const start of [candidate, (0, import_path3.resolve)(path)]) {
1477
+ for (let parent = (0, import_path3.dirname)(start); ; parent = (0, import_path3.dirname)(parent)) {
1478
+ ancestors.add(parent);
1479
+ if ((0, import_path3.dirname)(parent) === parent) break;
1480
+ }
1481
+ }
1482
+ for (const parent of ancestors) {
1483
+ const identity = await readFileIdentity(parent);
1484
+ const library = await (0, import_wiki_graph_core2.findWikiGraphLibraryByPhysicalIdentity)(
1485
+ identity,
1486
+ new NodeDirectory(parent).identity
1318
1487
  );
1488
+ if (library !== void 0) {
1489
+ throw new WikiGraphArchiveOwnershipError(
1490
+ `Standalone archive path belongs to registered library ${(0, import_wiki_graph_core2.formatWikiGraphLibraryUri)(
1491
+ library.isDefault ? void 0 : library.publicId
1492
+ )}: ${path}. Scan the library, then address the archive by its library UUID URI.`
1493
+ );
1494
+ }
1319
1495
  }
1320
1496
  return path;
1321
1497
  }
@@ -1373,48 +1549,35 @@ async function resolveLibraryLocation(target) {
1373
1549
  async function canonicalPath(path) {
1374
1550
  try {
1375
1551
  return await (0, import_promises3.realpath)(path);
1376
- } catch {
1552
+ } catch (error) {
1553
+ if (!(typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")))
1554
+ throw error;
1377
1555
  const absolute = (0, import_path3.resolve)(path);
1378
1556
  const parent = (0, import_path3.dirname)(absolute);
1379
1557
  return parent === absolute ? absolute : (0, import_path3.join)(await canonicalPath(parent), (0, import_path3.basename)(absolute));
1380
1558
  }
1381
1559
  }
1382
- function isWithin(root, candidate) {
1383
- const child = (0, import_path3.relative)(root, candidate);
1384
- return child === "" || !child.startsWith("..") && !(0, import_path3.isAbsolute)(child);
1385
- }
1386
- async function findMatchingMembers(libraries, candidate, candidateIdentity) {
1560
+ async function findMatchingMembers(candidate, candidateIdentity) {
1561
+ if (candidateIdentity === void 0) return [];
1562
+ const archives = await (0, import_wiki_graph_core2.findWikiGraphLibraryArchivePhysicalAliases)(candidateIdentity);
1387
1563
  const members = [];
1388
- for (const library of libraries) {
1389
- const archives = await (0, import_wiki_graph_core2.listWikiGraphLibraryArchives)({
1390
- isDefault: library.isDefault,
1391
- kind: "scope",
1392
- ...library.isDefault ? {} : { publicId: library.publicId }
1393
- });
1394
- for (const archive of archives) {
1395
- const physical = archive.file ?? archive.directory;
1396
- if (physical === void 0) continue;
1564
+ for (const archive of archives) {
1565
+ const parsed = (0, import_wiki_graph_core2.parseWikiGraphLibraryUri)(archive.libraryUri);
1566
+ const library = await (0, import_wiki_graph_core2.resolveWikiGraphLibrary)(parsed);
1567
+ const physical = archive.file ?? archive.directory;
1568
+ if (library !== void 0 && physical !== void 0)
1397
1569
  members.push({
1398
1570
  archive,
1399
1571
  library,
1400
1572
  memberPath: getNodeResourcePath(physical)
1401
1573
  });
1402
- }
1403
1574
  }
1404
1575
  const exact = [];
1405
1576
  for (const member of members) {
1406
- if (await canonicalPath(member.memberPath) === candidate) {
1577
+ if (await canonicalPath(member.memberPath) === candidate)
1407
1578
  exact.push(member);
1408
- }
1409
- }
1410
- if (exact.length > 0 || candidateIdentity === void 0) return exact;
1411
- const identityMatches = [];
1412
- for (const member of members) {
1413
- if (await readFileIdentity(member.memberPath) === candidateIdentity) {
1414
- identityMatches.push(member);
1415
- }
1416
1579
  }
1417
- return identityMatches;
1580
+ return exact.length > 0 ? exact : members;
1418
1581
  }
1419
1582
  function requireUnambiguousManagedMatch(path, matches) {
1420
1583
  if (matches.length === 1) return matches[0];
@@ -1426,8 +1589,10 @@ async function readFileIdentity(path) {
1426
1589
  try {
1427
1590
  const value = await (0, import_promises3.stat)(path);
1428
1591
  return `${value.dev}:${value.ino}`;
1429
- } catch {
1430
- return void 0;
1592
+ } catch (error) {
1593
+ if (typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"))
1594
+ return void 0;
1595
+ throw error;
1431
1596
  }
1432
1597
  }
1433
1598
 
@@ -1489,11 +1654,15 @@ var WikiGraphConversionManager = class {
1489
1654
  if (!("path" in options.input)) {
1490
1655
  throw new Error("wikg input requires a file path.");
1491
1656
  }
1657
+ const inputPath = options.input.path;
1492
1658
  await app.openSession(
1493
- new NodeFile(
1494
- await assertStandaloneWikiGraphArchivePath(options.input.path)
1495
- ),
1659
+ new NodeFile(await assertStandaloneWikiGraphArchivePath(inputPath)),
1496
1660
  write
1661
+ ).catch(
1662
+ (error) => rethrowArchiveSchemaError(error, {
1663
+ kind: "standalone",
1664
+ path: inputPath
1665
+ })
1497
1666
  );
1498
1667
  } else if ("stream" in options.input) {
1499
1668
  await app.digestTextStreamSession(
@@ -1884,6 +2053,12 @@ var import_wiki_graph_core6 = require("wiki-graph-core");
1884
2053
  async function writeWikiGraphArchiveLocation(location, operation, options = {}) {
1885
2054
  const cacheOnly = options.searchIndexWritebackPolicy === "cache";
1886
2055
  const write = async (archiveFile = location.archiveFile) => {
2056
+ if (cacheOnly) {
2057
+ return await new import_wiki_graph_core6.WikiGraphArchiveFile(archiveFile).readDocument(
2058
+ operation,
2059
+ { searchIndexWritebackPolicy: "cache" }
2060
+ );
2061
+ }
1887
2062
  const writeOptions = {
1888
2063
  ...cacheOnly ? {} : { derivedStateKeys: [location.archiveKey, location.archivePath] },
1889
2064
  ...options.invalidateContinuationCursors === void 0 ? {} : {
@@ -2201,10 +2376,15 @@ var WikiGraphArchiveManager = class {
2201
2376
  }, options.signal);
2202
2377
  }
2203
2378
  async open(target, options = {}) {
2204
- const location = await this.#runtime.run(
2205
- async () => await resolveWikiGraphArchiveLocation(target),
2206
- options.signal
2207
- );
2379
+ const location = await this.#runtime.run(async () => {
2380
+ const location2 = await resolveWikiGraphArchiveLocation(target);
2381
+ try {
2382
+ await (0, import_wiki_graph_core7.ensureWikiGraphArchiveSchemaCurrent)(location2.archiveFile);
2383
+ } catch (error) {
2384
+ rethrowArchiveSchemaError(error, target);
2385
+ }
2386
+ return location2;
2387
+ }, options.signal);
2208
2388
  return new WikiGraphArchiveHandle(this.#runtime, location);
2209
2389
  }
2210
2390
  };
@@ -2255,15 +2435,11 @@ var WikiGraphArchiveHandle = class {
2255
2435
  options.queryMode,
2256
2436
  options.signal
2257
2437
  );
2258
- const result = await this.#writeDocument(
2438
+ const result = await this.#readDocument(
2259
2439
  async (document) => {
2260
2440
  const chapters = await this.#resolveQueryChapters(document, options, {
2261
2441
  embeddingProvider
2262
2442
  });
2263
- await ensureArchiveSearchIndex(document, {
2264
- ...chapters === void 0 ? {} : { chapters },
2265
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2266
- });
2267
2443
  return await (0, import_wiki_graph_core7.findArchiveObjects)(document, query, {
2268
2444
  ...withoutOperationAndScope(options),
2269
2445
  archiveKey: this.archiveKey,
@@ -2272,7 +2448,6 @@ var WikiGraphArchiveHandle = class {
2272
2448
  });
2273
2449
  },
2274
2450
  {
2275
- searchIndexWritebackPolicy: "cache",
2276
2451
  ...options.signal === void 0 ? {} : { signal: options.signal }
2277
2452
  }
2278
2453
  );
@@ -2377,6 +2552,7 @@ var WikiGraphArchiveHandle = class {
2377
2552
  async (document) => {
2378
2553
  const chapters = await this.#resolveScope(document, options);
2379
2554
  await ensureArchiveSearchIndex(document, {
2555
+ rebuild: true,
2380
2556
  ...chapters === void 0 ? {} : { chapters },
2381
2557
  ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2382
2558
  });
@@ -2666,15 +2842,11 @@ var WikiGraphArchiveHandle = class {
2666
2842
  options.queryMode,
2667
2843
  options.signal
2668
2844
  );
2669
- const result = await this.#writeDocument(
2845
+ const result = await this.#readDocument(
2670
2846
  async (document) => {
2671
2847
  const chapters = await this.#resolveQueryChapters(document, options, {
2672
2848
  embeddingProvider
2673
2849
  });
2674
- await ensureArchiveSearchIndex(document, {
2675
- ...chapters === void 0 ? {} : { chapters },
2676
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2677
- });
2678
2850
  return await (0, import_wiki_graph_core7.listRelatedArchiveObjects)(document, objectUri, {
2679
2851
  ...withoutOperation(options),
2680
2852
  ...embeddingProvider === void 0 ? {} : { embeddingProvider },
@@ -2682,7 +2854,6 @@ var WikiGraphArchiveHandle = class {
2682
2854
  });
2683
2855
  },
2684
2856
  {
2685
- searchIndexWritebackPolicy: "cache",
2686
2857
  ...options.signal === void 0 ? {} : { signal: options.signal }
2687
2858
  }
2688
2859
  );
@@ -2726,15 +2897,11 @@ var WikiGraphArchiveHandle = class {
2726
2897
  options.queryMode,
2727
2898
  options.signal
2728
2899
  );
2729
- const result = await this.#writeDocument(
2900
+ const result = await this.#readDocument(
2730
2901
  async (document) => {
2731
2902
  const chapters = await this.#resolveQueryChapters(document, options, {
2732
2903
  embeddingProvider
2733
2904
  });
2734
- await ensureArchiveSearchIndex(document, {
2735
- ...chapters === void 0 ? {} : { chapters },
2736
- ...embeddingProvider === void 0 ? {} : { embeddingProvider }
2737
- });
2738
2905
  return await (0, import_wiki_graph_core7.listArchiveEvidence)(document, objectUri, {
2739
2906
  ...withoutOperation(options),
2740
2907
  ...embeddingProvider === void 0 ? {} : { embeddingProvider },
@@ -2742,7 +2909,6 @@ var WikiGraphArchiveHandle = class {
2742
2909
  });
2743
2910
  },
2744
2911
  {
2745
- searchIndexWritebackPolicy: "cache",
2746
2912
  ...options.signal === void 0 ? {} : { signal: options.signal }
2747
2913
  }
2748
2914
  );
@@ -2859,6 +3025,8 @@ var WikiGraphArchiveHandle = class {
2859
3025
  this.#location.archiveFile
2860
3026
  ).readDocument(operation),
2861
3027
  options.signal
3028
+ ).catch(
3029
+ (error) => rethrowArchiveSchemaError(error, this.#location.target)
2862
3030
  );
2863
3031
  }
2864
3032
  async #writeDocument(operation, options = {}) {
@@ -2870,33 +3038,32 @@ var WikiGraphArchiveHandle = class {
2870
3038
  searchIndexWritebackPolicy: options.searchIndexWritebackPolicy
2871
3039
  }
2872
3040
  });
2873
- }, options.signal);
3041
+ }, options.signal).catch(
3042
+ (error) => rethrowArchiveSchemaError(error, this.#location.target)
3043
+ );
2874
3044
  }
2875
3045
  async #resolveScope(document, options) {
2876
3046
  if (options.chapters !== void 0) return options.chapters;
2877
3047
  return (await resolveArchiveScope(document, this.objectUri, options.depth))?.chapterIds;
2878
3048
  }
2879
3049
  async #resolveQueryChapters(document, options, capabilities) {
2880
- const chapters = await this.#resolveScope(document, options);
3050
+ const parsed = parseChapterScopePath(this.objectUri);
3051
+ const chapters = options.chapters ?? (parsed === void 0 || parsed.kind === "collection" && options.depth === void 0 ? void 0 : await (0, import_wiki_graph_core7.resolveIndexedArchiveChapterScope)(
3052
+ document,
3053
+ parsed.kind === "chapter" ? parsed.chapterPath : void 0,
3054
+ options.depth
3055
+ ));
2881
3056
  const coverageOptions = {
2882
3057
  ...chapters === void 0 ? {} : { chapters },
2883
3058
  ...capabilities.embeddingProvider === void 0 ? {} : { embeddingProvider: capabilities.embeddingProvider },
2884
3059
  requireEmbeddingProvider: true,
2885
3060
  ...options.queryMode === void 0 ? {} : { queryMode: options.queryMode }
2886
3061
  };
2887
- if (options.skipUnindexed !== true) {
2888
- await (0, import_wiki_graph_core7.assertArchiveIndexArtifactsReady)(document, coverageOptions);
2889
- return chapters;
2890
- }
2891
- const queryable = await (0, import_wiki_graph_core7.listArchiveQueryableChapterIds)(document, {
2892
- ...coverageOptions
3062
+ await (0, import_wiki_graph_core7.assertArchiveQueryReady)(document, {
3063
+ ...coverageOptions,
3064
+ ...options.skipUnindexed === void 0 ? {} : { skipUnindexed: options.skipUnindexed }
2893
3065
  });
2894
- if (queryable.length === 0) {
2895
- throw new Error(
2896
- "Wiki Graph query is not ready. No chapters in this scope have a current FTS artifact or source embedding artifact."
2897
- );
2898
- }
2899
- return queryable;
3066
+ return chapters;
2900
3067
  }
2901
3068
  async #resolveQueryEmbeddingProvider(queryMode, signal) {
2902
3069
  if (queryMode === "fts") return void 0;
@@ -2915,6 +3082,10 @@ var WikiGraphArchiveHandle = class {
2915
3082
  async function ensureArchiveSearchIndex(document, options = {}) {
2916
3083
  const scope = options.chapters === void 0 ? {} : { chapters: options.chapters };
2917
3084
  if (await (0, import_wiki_graph_core7.isArchiveSearchIndexCurrent)(document, scope)) return;
3085
+ if (options.rebuild !== true)
3086
+ throw new Error(
3087
+ "Archive search index is missing or dirty. Run `wg <archive-uri>/index sync` explicitly before querying."
3088
+ );
2918
3089
  await (0, import_wiki_graph_core7.rebuildArchiveSearchIndex)(document, void 0, {
2919
3090
  ...scope,
2920
3091
  ...options.embeddingProvider === void 0 ? {} : { embeddingProvider: options.embeddingProvider }