@forgeax/engine-pack 0.1.3 → 0.1.4

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 (95) hide show
  1. package/README.md +51 -3
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/owner-chain.integration.test.d.ts +2 -0
  4. package/dist/__tests__/owner-chain.integration.test.d.ts.map +1 -0
  5. package/dist/__tests__/package-finalizer.contract.test.d.ts +2 -0
  6. package/dist/__tests__/package-finalizer.contract.test.d.ts.map +1 -0
  7. package/dist/__tests__/runtime.browser.test.d.ts +2 -0
  8. package/dist/__tests__/runtime.browser.test.d.ts.map +1 -0
  9. package/dist/__tests__/scanner-inventory.contract.test.d.ts +2 -0
  10. package/dist/__tests__/scanner-inventory.contract.test.d.ts.map +1 -0
  11. package/dist/artifact-path.mjs +53 -0
  12. package/dist/artifact-path.mjs.map +1 -0
  13. package/dist/atlas/shelf-pack.d.ts.map +1 -1
  14. package/dist/build.d.ts +17 -0
  15. package/dist/build.d.ts.map +1 -0
  16. package/dist/build.mjs +10168 -0
  17. package/dist/build.mjs.map +1 -0
  18. package/dist/builtin.d.ts +20 -0
  19. package/dist/builtin.d.ts.map +1 -1
  20. package/dist/builtin.mjs +141 -0
  21. package/dist/builtin.mjs.map +1 -0
  22. package/dist/catalog-builder.d.ts +43 -0
  23. package/dist/catalog-builder.d.ts.map +1 -0
  24. package/dist/catalog-delta.d.ts +11 -0
  25. package/dist/catalog-delta.d.ts.map +1 -0
  26. package/dist/catalog-projection.d.ts +91 -0
  27. package/dist/catalog-projection.d.ts.map +1 -0
  28. package/dist/cli-asset.mjs +231 -484
  29. package/dist/cli-asset.mjs.map +1 -1
  30. package/dist/index.mjs +83 -1
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/material-cook.d.ts +2 -0
  33. package/dist/material-cook.d.ts.map +1 -0
  34. package/dist/material-cook.mjs +193 -0
  35. package/dist/material-cook.mjs.map +1 -0
  36. package/dist/mesh-bin-contract.mjs +96 -0
  37. package/dist/mesh-bin-contract.mjs.map +1 -0
  38. package/dist/native-cooker-registry.d.ts +19 -0
  39. package/dist/native-cooker-registry.d.ts.map +1 -1
  40. package/dist/native-cooker.mjs +37 -0
  41. package/dist/native-cooker.mjs.map +1 -1
  42. package/dist/package-finalizer.d.ts +121 -0
  43. package/dist/package-finalizer.d.ts.map +1 -0
  44. package/dist/resolve-asset-source.d.ts.map +1 -1
  45. package/dist/resolve-asset-source.mjs +16 -6
  46. package/dist/resolve-asset-source.mjs.map +1 -1
  47. package/dist/runtime-publication.d.ts +44 -0
  48. package/dist/runtime-publication.d.ts.map +1 -0
  49. package/dist/runtime.d.ts +8 -0
  50. package/dist/runtime.d.ts.map +1 -0
  51. package/dist/runtime.mjs +7261 -0
  52. package/dist/runtime.mjs.map +1 -0
  53. package/dist/scanner.d.ts +87 -54
  54. package/dist/scanner.d.ts.map +1 -1
  55. package/dist/scanner.mjs +258 -454
  56. package/dist/scanner.mjs.map +1 -1
  57. package/dist/scriptable-pack-node.d.ts +3 -8
  58. package/dist/scriptable-pack-node.d.ts.map +1 -1
  59. package/dist/scriptable-pack-node.mjs +93 -9
  60. package/dist/scriptable-pack-node.mjs.map +1 -1
  61. package/dist/scriptable-pack-worker.mjs +1 -0
  62. package/dist/scriptable-pack-worker.mjs.map +1 -1
  63. package/dist/scriptable-pack.d.ts +33 -0
  64. package/dist/scriptable-pack.d.ts.map +1 -1
  65. package/dist/scriptable-pack.mjs +91 -2
  66. package/dist/scriptable-pack.mjs.map +1 -1
  67. package/dist/topology.d.ts +1 -1
  68. package/dist/topology.d.ts.map +1 -1
  69. package/package.json +27 -2
  70. package/src/__tests__/mesh-bin-consumer-surface.unit.test.ts +2 -1
  71. package/src/__tests__/owner-chain.integration.test.ts +78 -0
  72. package/src/__tests__/package-finalizer.contract.test.ts +105 -0
  73. package/src/__tests__/runtime.browser.test.ts +15 -0
  74. package/src/__tests__/scanner-inventory.contract.test.ts +167 -0
  75. package/src/__tests__/scanner-inventory.test.ts +16 -12
  76. package/src/__tests__/scriptable-pack.unit.test.ts +42 -0
  77. package/src/atlas/shelf-pack.ts +20 -24
  78. package/src/build.ts +137 -0
  79. package/src/builtin.ts +38 -0
  80. package/src/catalog-builder.ts +313 -0
  81. package/src/catalog-delta.ts +189 -0
  82. package/src/catalog-projection.ts +344 -0
  83. package/src/cli-asset.ts +1 -5
  84. package/src/index.ts +2 -2
  85. package/src/material-cook.ts +13 -0
  86. package/src/native-cooker-registry.ts +72 -0
  87. package/src/package-finalizer.ts +394 -0
  88. package/src/resolve-asset-source.ts +2 -7
  89. package/src/runtime-publication.ts +190 -0
  90. package/src/runtime.ts +23 -0
  91. package/src/scanner.ts +289 -290
  92. package/src/scriptable-pack-node.ts +27 -23
  93. package/src/scriptable-pack-worker.ts +2 -0
  94. package/src/scriptable-pack.ts +123 -1
  95. package/src/topology.ts +2 -1
@@ -6870,6 +6870,20 @@ function invalidPath(locator, context) {
6870
6870
  }
6871
6871
 
6872
6872
  // src/atlas/shelf-pack.ts
6873
+ function sizeExceeded(image, maxAtlasSize) {
6874
+ return {
6875
+ ok: false,
6876
+ error: {
6877
+ code: "atlas-size-exceeded",
6878
+ detail: {
6879
+ name: image.name,
6880
+ width: image.width,
6881
+ height: image.height,
6882
+ maxAtlasSize
6883
+ }
6884
+ }
6885
+ };
6886
+ }
6873
6887
  function nextPow2(n) {
6874
6888
  if (n <= 1) return 1;
6875
6889
  let p = 1;
@@ -6886,18 +6900,7 @@ function shelfPack(images, opts) {
6886
6900
  }
6887
6901
  for (const img of images) {
6888
6902
  if (img.width > maxAtlasSize || img.height > maxAtlasSize) {
6889
- return {
6890
- ok: false,
6891
- error: {
6892
- code: "atlas-size-exceeded",
6893
- detail: {
6894
- name: img.name,
6895
- width: img.width,
6896
- height: img.height,
6897
- maxAtlasSize
6898
- }
6899
- }
6900
- };
6903
+ return sizeExceeded(img, maxAtlasSize);
6901
6904
  }
6902
6905
  }
6903
6906
  const sorted = [...images].sort((a, b) => {
@@ -6926,18 +6929,7 @@ function shelfPack(images, opts) {
6926
6929
  currentShelfHeight = img.height;
6927
6930
  }
6928
6931
  if (cursorY + img.height > maxAtlasSize) {
6929
- return {
6930
- ok: false,
6931
- error: {
6932
- code: "atlas-size-exceeded",
6933
- detail: {
6934
- name: img.name,
6935
- width: img.width,
6936
- height: img.height,
6937
- maxAtlasSize
6938
- }
6939
- }
6940
- };
6932
+ return sizeExceeded(img, maxAtlasSize);
6941
6933
  }
6942
6934
  regions.push({ name: img.name, x: cursorX, y: cursorY, w: img.width, h: img.height });
6943
6935
  cursorX += img.width;
@@ -7502,11 +7494,23 @@ function validateProducerOutputs(outputs) {
7502
7494
  }
7503
7495
  return { ok: true, value: outputs };
7504
7496
  }
7497
+
7498
+ // src/deriveAssetName.ts
7505
7499
  function baseName(p) {
7506
7500
  const trimmed = p.replace(/[/\\]+$/, "");
7507
7501
  const idx = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
7508
7502
  return idx === -1 ? trimmed : trimmed.slice(idx + 1);
7509
7503
  }
7504
+ function deriveAssetName(packagePath2, assetCount, storedName) {
7505
+ if (packagePath2 === null) {
7506
+ return "";
7507
+ }
7508
+ {
7509
+ return baseName(packagePath2);
7510
+ }
7511
+ }
7512
+
7513
+ // src/resolve-asset-source.ts
7510
7514
  function deriveSourceName(metaFileName) {
7511
7515
  return metaFileName.replace(/\.meta\.json$/, "");
7512
7516
  }
@@ -7518,7 +7522,7 @@ function isPathEscape(pathDir, resolved) {
7518
7522
  function resolveAssetSource(metaPath, source, paths) {
7519
7523
  if (source === void 0) {
7520
7524
  const metaDir = dirname(metaPath);
7521
- const metaName = baseName(metaPath);
7525
+ const metaName = deriveAssetName(metaPath);
7522
7526
  const derived = deriveSourceName(metaName);
7523
7527
  return ok(resolve(metaDir, derived));
7524
7528
  }
@@ -8027,6 +8031,22 @@ var SCRIPTABLE_PACK_ASSET_KINDS = [
8027
8031
  function isScriptablePackAssetKind(value) {
8028
8032
  return SCRIPTABLE_PACK_ASSET_KINDS.includes(value);
8029
8033
  }
8034
+ function sceneComponentFieldType(value) {
8035
+ if (typeof value === "string") return value;
8036
+ if (isRecord2(value) && typeof value.type === "string") return value.type;
8037
+ return void 0;
8038
+ }
8039
+ function projectScriptablePackSceneComponents(components) {
8040
+ return (components ?? []).map((component) => ({
8041
+ name: component.name,
8042
+ fields: Object.fromEntries(
8043
+ Object.entries(component.fields).map(([fieldName, field]) => [
8044
+ fieldName,
8045
+ sceneComponentFieldType(field)
8046
+ ])
8047
+ )
8048
+ }));
8049
+ }
8030
8050
  var SCRIPTABLE_PACK_REQUEST_ID_SCHEMA = {
8031
8051
  type: "string",
8032
8052
  minLength: 1,
@@ -8252,11 +8272,20 @@ function freezeDefinition(definition) {
8252
8272
  guid.slice()
8253
8273
  ])
8254
8274
  );
8275
+ const sceneComponents = definition.sceneComponents === void 0 ? void 0 : Object.freeze(
8276
+ projectScriptablePackSceneComponents(definition.sceneComponents).map(
8277
+ (component) => Object.freeze({
8278
+ ...component,
8279
+ fields: Object.freeze({ ...component.fields })
8280
+ })
8281
+ )
8282
+ );
8255
8283
  return Object.freeze({
8256
8284
  ...definition,
8257
8285
  packageId: definition.packageId.slice(),
8258
8286
  assets: Object.freeze(assets),
8259
- externalAssets: Object.freeze(externalAssets)
8287
+ externalAssets: Object.freeze(externalAssets),
8288
+ ...sceneComponents === void 0 ? {} : { sceneComponents }
8260
8289
  });
8261
8290
  }
8262
8291
  function validateScriptablePackDefinition(value, sourcePath) {
@@ -8287,6 +8316,63 @@ function validateScriptablePackDefinition(value, sourcePath) {
8287
8316
  sourcePath
8288
8317
  );
8289
8318
  }
8319
+ if (value.sceneComponents !== void 0) {
8320
+ if (!Array.isArray(value.sceneComponents)) {
8321
+ return invalid(
8322
+ "$.sceneComponents",
8323
+ "an array of component tokens or neutral schema rows when present",
8324
+ value.sceneComponents,
8325
+ sourcePath
8326
+ );
8327
+ }
8328
+ const componentNames = /* @__PURE__ */ new Set();
8329
+ for (const [componentIndex, component] of value.sceneComponents.entries()) {
8330
+ if (!isRecord2(component)) {
8331
+ return invalid(
8332
+ `$.sceneComponents[${componentIndex}]`,
8333
+ "a component token or neutral schema row",
8334
+ component,
8335
+ sourcePath
8336
+ );
8337
+ }
8338
+ if (typeof component.name !== "string" || component.name.trim().length === 0) {
8339
+ return invalid(
8340
+ `$.sceneComponents[${componentIndex}].name`,
8341
+ "a non-empty component name",
8342
+ component.name,
8343
+ sourcePath
8344
+ );
8345
+ }
8346
+ if (componentNames.has(component.name)) {
8347
+ return invalid(
8348
+ `$.sceneComponents[${componentIndex}].name`,
8349
+ "component names to be unique within one ScriptablePack",
8350
+ component.name,
8351
+ sourcePath
8352
+ );
8353
+ }
8354
+ componentNames.add(component.name);
8355
+ if (!isRecord2(component.fields)) {
8356
+ return invalid(
8357
+ `$.sceneComponents[${componentIndex}].fields`,
8358
+ "a field-name to schema-type object",
8359
+ component.fields,
8360
+ sourcePath
8361
+ );
8362
+ }
8363
+ for (const [fieldName, field] of Object.entries(component.fields)) {
8364
+ const type = sceneComponentFieldType(field);
8365
+ if (fieldName.trim().length === 0 || type === void 0 || type.trim().length === 0) {
8366
+ return invalid(
8367
+ `$.sceneComponents[${componentIndex}].fields`,
8368
+ "field names with non-empty string schema types",
8369
+ field,
8370
+ sourcePath
8371
+ );
8372
+ }
8373
+ }
8374
+ }
8375
+ }
8290
8376
  if (typeof value.build !== "function") {
8291
8377
  return invalid("$.build", "a build(assetReader) function", value.build, sourcePath);
8292
8378
  }
@@ -8390,7 +8476,7 @@ function scriptablePackWorkerExecArgv() {
8390
8476
  const inherited = process.execArgv.filter((arg) => !arg.startsWith("--input-type"));
8391
8477
  return inherited.includes(IMPORT_META_RESOLVE_FLAG) ? inherited : [...inherited, IMPORT_META_RESOLVE_FLAG];
8392
8478
  }
8393
- async function resolveRelativeSourceImport(sourcePath, specifier) {
8479
+ async function resolveRelativeImport(sourcePath, specifier) {
8394
8480
  if (!specifier.startsWith(".")) return void 0;
8395
8481
  const raw = resolve(dirname(sourcePath), specifier);
8396
8482
  const candidates = extname(raw).length > 0 ? [raw] : [
@@ -8411,19 +8497,20 @@ async function resolveRelativeSourceImport(sourcePath, specifier) {
8411
8497
  }
8412
8498
  return void 0;
8413
8499
  }
8414
- async function inventoryScriptablePackSource(sourcePath) {
8415
- const pending = [await realpath(sourcePath)];
8500
+ async function inventoryScriptablePackSource(sourcePath, initialSourceText) {
8501
+ const root = await realpath(sourcePath);
8502
+ const pending = [root];
8416
8503
  const seen = /* @__PURE__ */ new Set();
8417
8504
  const entries = [];
8418
8505
  while (pending.length > 0) {
8419
8506
  const path = pending.pop();
8420
8507
  if (path === void 0 || seen.has(path)) continue;
8421
8508
  seen.add(path);
8422
- const bytes = await readFile(path);
8509
+ const bytes = path === root && initialSourceText !== void 0 ? new TextEncoder().encode(initialSourceText) : await readFile(path);
8423
8510
  entries.push({ path, digest: `sha256:${createHash("sha256").update(bytes).digest("hex")}` });
8424
- const imports = ts.preProcessFile(new TextDecoder().decode(bytes), true, true).importedFiles;
8425
- for (const imported of imports) {
8426
- const resolved = await resolveRelativeSourceImport(path, imported.fileName);
8511
+ const source = new TextDecoder().decode(bytes);
8512
+ for (const imported of ts.preProcessFile(source, true, true).importedFiles) {
8513
+ const resolved = await resolveRelativeImport(path, imported.fileName);
8427
8514
  if (resolved !== void 0) pending.push(await realpath(resolved));
8428
8515
  }
8429
8516
  }
@@ -8497,6 +8584,7 @@ var WorkerScriptablePackExecutor = class {
8497
8584
  if (message === null || typeof message !== "object") return;
8498
8585
  const value = message;
8499
8586
  if (value.kind === "loaded") {
8587
+ worker.unref();
8500
8588
  worker.off("message", onMessage);
8501
8589
  resolveLoad({
8502
8590
  default: value.definition === void 0 ? void 0 : {
@@ -8574,247 +8662,6 @@ function scriptablePackWorkerUrl() {
8574
8662
  const bundledWorker = new URL("./scriptable-pack-worker.mjs", import.meta.url);
8575
8663
  return existsSync(fileURLToPath(bundledWorker)) ? bundledWorker : new URL("../dist/scriptable-pack-worker.mjs", import.meta.url);
8576
8664
  }
8577
- var ReusableWorkerScriptablePackExecutor = class {
8578
- constructor(maxTasksPerWorker, release) {
8579
- this.maxTasksPerWorker = maxTasksPerWorker;
8580
- this.release = release;
8581
- this.worker = new Worker(scriptablePackWorkerUrl(), {
8582
- workerData: { mode: "reusable" },
8583
- execArgv: scriptablePackWorkerExecArgv(),
8584
- resourceLimits: { maxOldGenerationSizeMb: 256, maxYoungGenerationSizeMb: 64 }
8585
- });
8586
- this.worker.on("message", (message) => this.onMessage(message));
8587
- this.worker.on("error", (error) => {
8588
- this.failed = true;
8589
- this.rejectActive(error);
8590
- void this.dispose("failure");
8591
- });
8592
- this.worker.on("exit", (code) => {
8593
- if (code === 0 || this.disposal !== void 0) return;
8594
- this.failed = true;
8595
- this.rejectActive(new Error(`ScriptablePack worker exited with code ${code}`));
8596
- void this.dispose("failure");
8597
- });
8598
- this.worker.unref();
8599
- }
8600
- maxTasksPerWorker;
8601
- release;
8602
- worker;
8603
- compileRootReady = mkdtemp(resolve(tmpdir(), "forgeax-scriptable-pack-pool-"));
8604
- compileRoot;
8605
- nextLoadId = 0;
8606
- nextBuildId = 0;
8607
- pendingLoad;
8608
- build;
8609
- disposal;
8610
- forceDispose = false;
8611
- failed = false;
8612
- taskCount = 0;
8613
- released = false;
8614
- async load(sourcePath) {
8615
- const activeDisposal = this.disposal;
8616
- if (activeDisposal !== void 0) {
8617
- await activeDisposal;
8618
- if (this.failed) {
8619
- return Promise.reject(new Error("ScriptablePack executor is not leased"));
8620
- }
8621
- this.disposal = void 0;
8622
- }
8623
- this.released = false;
8624
- if (this.pendingLoad !== void 0 || this.build !== void 0) {
8625
- return Promise.reject(new Error("ScriptablePack executor already has an active task"));
8626
- }
8627
- const compileRoot = this.compileRoot ?? await this.compileRootReady;
8628
- if (this.disposal !== void 0) {
8629
- const disposal = this.disposal;
8630
- await disposal;
8631
- if (this.failed) {
8632
- return Promise.reject(new Error("ScriptablePack executor is not leased"));
8633
- }
8634
- this.disposal = void 0;
8635
- }
8636
- const loadId = this.nextLoadId++;
8637
- this.compileRoot = compileRoot;
8638
- this.taskCount += 1;
8639
- return new Promise((resolveLoad, rejectLoad) => {
8640
- this.pendingLoad = { id: loadId, resolve: resolveLoad, reject: rejectLoad };
8641
- try {
8642
- this.worker.postMessage({
8643
- kind: "load",
8644
- loadId,
8645
- sourcePath: resolve(sourcePath),
8646
- compileRoot
8647
- });
8648
- } catch (error) {
8649
- this.pendingLoad = void 0;
8650
- rejectLoad(error);
8651
- void this.dispose("failure");
8652
- }
8653
- });
8654
- }
8655
- dispose(reason = "complete") {
8656
- if (reason === "failure") this.forceDispose = true;
8657
- const activeDisposal = this.disposal;
8658
- if (activeDisposal !== void 0) {
8659
- return activeDisposal;
8660
- }
8661
- this.rejectActive(new Error(`ScriptablePack task disposed during ${reason}`));
8662
- this.disposal = (async () => {
8663
- const compileRoot = this.compileRoot ?? await this.compileRootReady;
8664
- const reusable = reason === "complete" && !this.failed && !this.forceDispose && this.taskCount < this.maxTasksPerWorker;
8665
- this.forceDispose = false;
8666
- if (!reusable) {
8667
- this.compileRoot = void 0;
8668
- await this.worker.terminate();
8669
- await rm(compileRoot, { recursive: true, force: true });
8670
- }
8671
- this.released = true;
8672
- this.disposal = void 0;
8673
- this.release(this, reusable);
8674
- })();
8675
- return this.disposal;
8676
- }
8677
- rejectActive(error) {
8678
- const loading = this.pendingLoad;
8679
- this.pendingLoad = void 0;
8680
- loading?.reject(error);
8681
- const building = this.build;
8682
- this.build = void 0;
8683
- building?.reject(error);
8684
- }
8685
- runBuild(reader) {
8686
- if (this.released || this.disposal !== void 0) {
8687
- return Promise.reject(new Error("ScriptablePack executor is not leased"));
8688
- }
8689
- if (this.build !== void 0) {
8690
- return Promise.reject(new Error("ScriptablePack worker already has an active build"));
8691
- }
8692
- const id = this.nextBuildId++;
8693
- return new Promise((resolveBuild, rejectBuild) => {
8694
- this.build = { id, reader, resolve: resolveBuild, reject: rejectBuild };
8695
- try {
8696
- this.worker.postMessage({ kind: "build", buildId: id });
8697
- } catch (error) {
8698
- this.build = void 0;
8699
- rejectBuild(error);
8700
- void this.dispose("failure");
8701
- }
8702
- });
8703
- }
8704
- onMessage(message) {
8705
- if (message === null || typeof message !== "object") return;
8706
- const value = message;
8707
- const loading = this.pendingLoad;
8708
- if (loading !== void 0 && value.kind === "loaded" && value.loadId === loading.id) {
8709
- this.pendingLoad = void 0;
8710
- loading.resolve({
8711
- default: value.definition === void 0 ? void 0 : {
8712
- ...value.definition,
8713
- build: (reader) => this.runBuild(reader)
8714
- }
8715
- });
8716
- return;
8717
- }
8718
- if (loading !== void 0 && value.kind === "load-threw" && value.loadId === loading.id) {
8719
- this.pendingLoad = void 0;
8720
- loading.reject(hydrateFailure(value.error));
8721
- return;
8722
- }
8723
- const active = this.build;
8724
- if (active === void 0 || value.buildId !== active.id) return;
8725
- if (value.kind === "asset-read" && typeof value.readId === "number") {
8726
- void active.reader.readByGuid(value.guid).then(
8727
- (result) => this.worker.postMessage({
8728
- kind: "asset-result",
8729
- readId: value.readId,
8730
- result: result.ok === true ? result : { ...result, error: serializeFailure(result.error) }
8731
- })
8732
- ).catch((error) => {
8733
- if (this.build?.id !== active.id) return;
8734
- this.build = void 0;
8735
- active.reject(error);
8736
- void this.dispose("failure");
8737
- });
8738
- return;
8739
- }
8740
- this.build = void 0;
8741
- if (value.kind === "build-result") active.resolve(value.result);
8742
- else if (value.kind === "build-threw") active.reject(hydrateFailure(value.error));
8743
- else this.build = active;
8744
- }
8745
- };
8746
- var DefaultScriptablePackModuleExecutorPool = class {
8747
- maxWorkers;
8748
- maxTasksPerWorker;
8749
- idle = [];
8750
- waiters = [];
8751
- executors = /* @__PURE__ */ new Set();
8752
- workerCount = 0;
8753
- closed = false;
8754
- constructor(options = {}) {
8755
- this.maxWorkers = Math.max(1, Math.trunc(options.maxWorkers ?? 2));
8756
- this.maxTasksPerWorker = Math.max(1, Math.trunc(options.maxTasksPerWorker ?? 32));
8757
- }
8758
- acquire() {
8759
- if (this.closed) return Promise.reject(new Error("ScriptablePack executor pool is closed"));
8760
- const executor = this.idle.pop();
8761
- if (executor !== void 0) return Promise.resolve(executor);
8762
- if (this.workerCount < this.maxWorkers) {
8763
- this.workerCount += 1;
8764
- return Promise.resolve(this.createExecutor());
8765
- }
8766
- return new Promise(
8767
- (resolveAcquire, rejectAcquire) => this.waiters.push({ resolve: resolveAcquire, reject: rejectAcquire })
8768
- );
8769
- }
8770
- async dispose() {
8771
- if (this.closed) return;
8772
- this.closed = true;
8773
- const waiters = this.waiters.splice(0);
8774
- for (const waiter of waiters) {
8775
- waiter.reject(new Error("ScriptablePack executor pool is closed"));
8776
- }
8777
- this.idle.splice(0);
8778
- await Promise.all([...this.executors].map((executor) => executor.dispose("failure")));
8779
- }
8780
- createExecutor() {
8781
- const executor = new ReusableWorkerScriptablePackExecutor(
8782
- this.maxTasksPerWorker,
8783
- (executor2, reusable) => {
8784
- if (this.closed) {
8785
- this.executors.delete(executor2);
8786
- if (!reusable) this.workerCount -= 1;
8787
- return;
8788
- }
8789
- if (!reusable) {
8790
- this.executors.delete(executor2);
8791
- this.workerCount -= 1;
8792
- } else {
8793
- this.idle.push(executor2);
8794
- }
8795
- this.drain();
8796
- }
8797
- );
8798
- this.executors.add(executor);
8799
- return executor;
8800
- }
8801
- drain() {
8802
- if (this.closed) return;
8803
- while (this.waiters.length > 0) {
8804
- const idle = this.idle.pop();
8805
- if (idle !== void 0) {
8806
- this.waiters.shift()?.resolve(idle);
8807
- continue;
8808
- }
8809
- if (this.workerCount >= this.maxWorkers) return;
8810
- this.workerCount += 1;
8811
- this.waiters.shift()?.resolve(this.createExecutor());
8812
- }
8813
- }
8814
- };
8815
- function createScriptablePackModuleExecutorPool(options = {}) {
8816
- return new DefaultScriptablePackModuleExecutorPool(options);
8817
- }
8818
8665
  function loadFailure(sourcePath, reason, phase, diagnostic, timeoutMs) {
8819
8666
  return err({
8820
8667
  code: "pack-source-load-failed",
@@ -8936,6 +8783,33 @@ var BLACKLIST = /* @__PURE__ */ new Set([
8936
8783
  "coverage"
8937
8784
  ]);
8938
8785
  var SCANNER_BLACKLIST = BLACKLIST;
8786
+ async function readValidatedJson(path, code, validate) {
8787
+ let raw;
8788
+ let parsed;
8789
+ try {
8790
+ raw = await readFile(path, "utf-8");
8791
+ parsed = JSON.parse(raw);
8792
+ } catch {
8793
+ return packErr(
8794
+ makePackError(code, {
8795
+ path,
8796
+ ajvErrors: [{ instancePath: "", message: "JSON parse failed" }]
8797
+ })
8798
+ );
8799
+ }
8800
+ if (!validate(parsed)) {
8801
+ return packErr(
8802
+ makePackError(code, {
8803
+ path,
8804
+ ajvErrors: (validate.errors ?? []).map((error) => ({
8805
+ instancePath: error.instancePath ?? "",
8806
+ message: error.message ?? "unknown ajv error"
8807
+ }))
8808
+ })
8809
+ );
8810
+ }
8811
+ return ok4({ raw, parsed });
8812
+ }
8939
8813
  function makePackError(code, detail) {
8940
8814
  return new PackError({
8941
8815
  code,
@@ -8958,7 +8832,7 @@ function* extractMountSourceGuids(asset) {
8958
8832
  yield resolved.toLowerCase();
8959
8833
  }
8960
8834
  }
8961
- async function scanInventory(roots, opts = {}) {
8835
+ async function scanValidated(roots, opts = {}, capture) {
8962
8836
  const rawPaths = [];
8963
8837
  const explicitRootSet = new Set(roots);
8964
8838
  async function traverse(dir) {
@@ -9003,34 +8877,10 @@ async function scanInventory(roots, opts = {}) {
9003
8877
  const scriptablePaths = rawPaths.filter((p) => p.endsWith(".pack.ts"));
9004
8878
  const guidToPath = /* @__PURE__ */ new Map();
9005
8879
  const packRefs = /* @__PURE__ */ new Map();
9006
- const scriptablePackMeta = /* @__PURE__ */ new Map();
9007
- const metaByGuid = /* @__PURE__ */ new Map();
9008
- const declarations = [];
9009
8880
  for (const packPath of packPaths) {
9010
- let parsed;
9011
- try {
9012
- const raw = await readFile(packPath, "utf-8");
9013
- parsed = JSON.parse(raw);
9014
- } catch {
9015
- return packErr(
9016
- makePackError("pack-malformed-pack", {
9017
- path: packPath,
9018
- ajvErrors: [{ instancePath: "", message: "JSON parse failed" }]
9019
- })
9020
- );
9021
- }
9022
- const valid = validatePack(parsed);
9023
- if (!valid) {
9024
- return packErr(
9025
- makePackError("pack-malformed-pack", {
9026
- path: packPath,
9027
- ajvErrors: (validatePack.errors ?? []).map((e) => ({
9028
- instancePath: e.instancePath,
9029
- message: e.message ?? "unknown ajv error"
9030
- }))
9031
- })
9032
- );
9033
- }
8881
+ const loaded = await readValidatedJson(packPath, "pack-malformed-pack", validatePack);
8882
+ if (!loaded.ok) return loaded;
8883
+ const { raw, parsed } = loaded.value;
9034
8884
  const packageContract = validateProducerContract(parsed);
9035
8885
  if (!packageContract.ok) {
9036
8886
  return packErr(
@@ -9072,7 +8922,12 @@ async function scanInventory(roots, opts = {}) {
9072
8922
  }
9073
8923
  }
9074
8924
  const topologyContract = validateProducerOutputs(
9075
- producerAssets
8925
+ producerAssets.map((asset, sourceIndex) => ({
8926
+ guid: asset.guid,
8927
+ kind: asset.kind,
8928
+ sourceIndex: asset.sourceIndex ?? sourceIndex,
8929
+ ...asset.sourceKey === void 0 ? {} : { sourceKey: asset.sourceKey }
8930
+ }))
9076
8931
  );
9077
8932
  if (!topologyContract.ok) {
9078
8933
  return packErr(
@@ -9113,66 +8968,17 @@ async function scanInventory(roots, opts = {}) {
9113
8968
  );
9114
8969
  }
9115
8970
  guidToPath.set(normalizedGuid, packPath);
9116
- const existingRefs = packRefs.get(normalizedGuid) ?? [];
9117
- for (const ref of asset.refs) {
9118
- existingRefs.push(ref.toLowerCase());
9119
- }
9120
- for (const guid of extractMountSourceGuids(asset)) {
9121
- existingRefs.push(guid);
9122
- }
9123
- packRefs.set(normalizedGuid, existingRefs);
9124
- }
9125
- const outputs = packObj.assets.map((asset) => ({
9126
- guid: asset.guid,
9127
- ...asset.sourceKey === void 0 ? {} : { sourceKey: asset.sourceKey },
9128
- ...asset.sourceIndex === void 0 ? {} : { sourceIndex: asset.sourceIndex },
9129
- kind: asset.kind,
9130
- ...asset.name === void 0 ? {} : { name: asset.name },
9131
- ...asset.execution === void 0 ? {} : { execution: asset.execution },
9132
- refs: asset.refs
9133
- }));
9134
- declarations.push({
9135
- sourcePath: packPath,
9136
- canonicalSourcePath: packPath.replace(/\\/g, "/"),
9137
- producer: "direct-pack",
9138
- ...packObj.packageId === void 0 ? {} : { packageId: packObj.packageId },
9139
- projectedMeta: {
9140
- schemaVersion: "2.0.0",
9141
- ...packObj.packageId === void 0 ? {} : { packageId: packObj.packageId },
9142
- outputs,
9143
- externalGuids: outputs.flatMap((output) => output.refs)
9144
- },
9145
- outputs,
9146
- externalGuids: outputs.flatMap((output) => output.refs),
9147
- diagnostics: []
9148
- });
8971
+ packRefs.set(normalizedGuid, [
8972
+ ...asset.refs.map((ref) => ref.toLowerCase()),
8973
+ ...extractMountSourceGuids(asset)
8974
+ ]);
8975
+ }
9149
8976
  }
9150
8977
  const { paths: assetPaths } = loadAssetConfig(process.cwd());
9151
8978
  for (const metaPath of metaPaths) {
9152
- let parsed;
9153
- try {
9154
- const raw = await readFile(metaPath, "utf-8");
9155
- parsed = JSON.parse(raw);
9156
- } catch {
9157
- return packErr(
9158
- makePackError("pack-malformed-meta", {
9159
- path: metaPath,
9160
- ajvErrors: [{ instancePath: "", message: "JSON parse failed" }]
9161
- })
9162
- );
9163
- }
9164
- const valid = validateMeta(parsed);
9165
- if (!valid) {
9166
- return packErr(
9167
- makePackError("pack-malformed-meta", {
9168
- path: metaPath,
9169
- ajvErrors: (validateMeta.errors ?? []).map((e) => ({
9170
- instancePath: e.instancePath,
9171
- message: e.message ?? "unknown ajv error"
9172
- }))
9173
- })
9174
- );
9175
- }
8979
+ const loaded = await readValidatedJson(metaPath, "pack-malformed-meta", validateMeta);
8980
+ if (!loaded.ok) return loaded;
8981
+ const { raw, parsed } = loaded.value;
9176
8982
  const metaContract = validateProducerContract(parsed);
9177
8983
  if (!metaContract.ok) {
9178
8984
  return packErr(
@@ -9203,13 +9009,10 @@ async function scanInventory(roots, opts = {}) {
9203
9009
  );
9204
9010
  }
9205
9011
  guidToPath.set(normalizedGuid, metaPath);
9206
- metaByGuid.set(normalizedGuid, metaPath);
9207
9012
  }
9208
9013
  const producerSubAssets = metaObj.subAssets.length > 1 ? metaObj.subAssets : [];
9209
9014
  if (producerSubAssets.length > 0) {
9210
- const topologyContract = validateProducerOutputs(
9211
- producerSubAssets
9212
- );
9015
+ const topologyContract = validateProducerOutputs(producerSubAssets);
9213
9016
  if (!topologyContract.ok) {
9214
9017
  return packErr(
9215
9018
  makePackError("pack-malformed-meta", {
@@ -9234,113 +9037,71 @@ async function scanInventory(roots, opts = {}) {
9234
9037
  })
9235
9038
  );
9236
9039
  }
9237
- const outputs = metaObj.subAssets.map((sub) => ({
9238
- guid: sub.guid,
9239
- ...sub.sourceKey === void 0 ? {} : { sourceKey: sub.sourceKey },
9240
- sourceIndex: sub.sourceIndex,
9241
- kind: sub.kind,
9242
- ...sub.name === void 0 ? {} : { name: sub.name },
9243
- refs: []
9244
- }));
9245
- const externalGuids = (metaObj.importSettings?.externalAssets ?? []).flatMap(
9246
- (entry) => typeof entry.guid === "string" ? [entry.guid] : []
9247
- );
9248
- declarations.push({
9249
- sourcePath: metaPath,
9250
- canonicalSourcePath: metaPath.replace(/\\/g, "/"),
9251
- producer: "source-meta",
9252
- ...metaObj.packageId === void 0 ? {} : { packageId: metaObj.packageId },
9253
- projectedMeta: {
9254
- ...metaObj.packageId === void 0 ? {} : { packageId: metaObj.packageId },
9255
- ...metaObj.importer === void 0 ? {} : { importer: metaObj.importer },
9256
- ...metaObj.source === void 0 ? {} : { source: metaObj.source },
9257
- ...metaObj.name === void 0 ? {} : { name: metaObj.name },
9258
- outputs,
9259
- externalGuids
9260
- },
9261
- outputs,
9262
- externalGuids,
9263
- diagnostics: []
9264
- });
9265
9040
  }
9266
- const scriptablePackExecutorPool = scriptablePaths.length === 0 || opts.scriptablePackLoad?.executor !== void 0 ? void 0 : createScriptablePackModuleExecutorPool();
9267
- try {
9268
- for (const sourcePath of scriptablePaths) {
9269
- const executor = await scriptablePackExecutorPool?.acquire();
9270
- const loaded = await loadScriptablePack(sourcePath, {
9271
- ...opts.scriptablePackLoad,
9272
- metadataOnly: true,
9273
- ...executor === void 0 ? {} : { executor }
9274
- });
9275
- if (!loaded.ok) {
9276
- const diagnostic = "diagnostic" in loaded.error.detail ? loaded.error.detail.diagnostic : void 0;
9277
- return packErr(
9278
- makePackError("pack-malformed-meta", {
9279
- path: sourcePath,
9280
- ajvErrors: [
9281
- {
9282
- instancePath: "",
9283
- message: diagnostic === void 0 ? loaded.error.code : `${loaded.error.code}: ${diagnostic}`
9284
- }
9285
- ]
9286
- })
9287
- );
9288
- }
9289
- const meta = projectScriptablePackMeta(loaded.value, sourcePath);
9290
- scriptablePackMeta.set(sourcePath, meta);
9291
- const sourceClosure = await inventoryScriptablePackSource(sourcePath);
9292
- const topology = validateProducerOutputs(
9293
- meta.subAssets
9041
+ for (const sourcePath of scriptablePaths) {
9042
+ let source;
9043
+ try {
9044
+ source = await readFile(sourcePath, "utf8");
9045
+ } catch {
9046
+ return packErr(
9047
+ makePackError("pack-malformed-meta", {
9048
+ path: sourcePath,
9049
+ ajvErrors: [{ instancePath: "", message: "ScriptablePack source read failed" }]
9050
+ })
9051
+ );
9052
+ }
9053
+ const loaded = await loadScriptablePack(sourcePath, {
9054
+ ...opts.scriptablePack ?? {},
9055
+ ...{ metadataOnly: true }
9056
+ });
9057
+ if (!loaded.ok) {
9058
+ const diagnostic = "diagnostic" in loaded.error.detail ? loaded.error.detail.diagnostic : void 0;
9059
+ return packErr(
9060
+ makePackError("pack-malformed-meta", {
9061
+ path: sourcePath,
9062
+ ajvErrors: [
9063
+ {
9064
+ instancePath: "",
9065
+ message: diagnostic === void 0 ? loaded.error.code : `${loaded.error.code}: ${diagnostic}`
9066
+ }
9067
+ ]
9068
+ })
9294
9069
  );
9295
- if (!topology.ok) {
9070
+ }
9071
+ let sourceClosure;
9072
+ try {
9073
+ sourceClosure = await inventoryScriptablePackSource(sourcePath, source);
9074
+ } catch {
9075
+ return packErr(
9076
+ makePackError("pack-malformed-meta", {
9077
+ path: sourcePath,
9078
+ ajvErrors: [{ instancePath: "", message: "ScriptablePack source closure read failed" }]
9079
+ })
9080
+ );
9081
+ }
9082
+ const meta = projectScriptablePackMeta(loaded.value, sourcePath);
9083
+ const topology = validateProducerOutputs(meta.subAssets);
9084
+ if (!topology.ok) {
9085
+ return packErr(
9086
+ makePackError("pack-malformed-meta", {
9087
+ path: sourcePath,
9088
+ ajvErrors: [{ instancePath: "/subAssets", message: topology.error.code }]
9089
+ })
9090
+ );
9091
+ }
9092
+ ({
9093
+ sourceRevision: `sha256:${createHash("sha256").update(source).digest("hex")}`,
9094
+ definition: loaded.value});
9095
+ for (const sub of meta.subAssets) {
9096
+ const guid = sub.guid.toLowerCase();
9097
+ const existing = guidToPath.get(guid);
9098
+ if (existing !== void 0) {
9296
9099
  return packErr(
9297
- makePackError("pack-malformed-meta", {
9298
- path: sourcePath,
9299
- ajvErrors: [{ instancePath: "/subAssets", message: topology.error.code }]
9300
- })
9100
+ makePackError("pack-guid-collision", { paths: [existing, sourcePath], guid })
9301
9101
  );
9302
9102
  }
9303
- for (const sub of meta.subAssets) {
9304
- const guid = sub.guid.toLowerCase();
9305
- const existing = guidToPath.get(guid);
9306
- if (existing !== void 0) {
9307
- return packErr(
9308
- makePackError("pack-guid-collision", { paths: [existing, sourcePath], guid })
9309
- );
9310
- }
9311
- guidToPath.set(guid, sourcePath);
9312
- }
9313
- const outputs = meta.subAssets.map((sub) => ({
9314
- guid: sub.guid,
9315
- sourceKey: sub.sourceKey,
9316
- sourceIndex: sub.sourceIndex,
9317
- kind: sub.kind,
9318
- ...sub.name === void 0 ? {} : { name: sub.name },
9319
- refs: []
9320
- }));
9321
- const externalGuids = meta.importSettings.externalAssets.map((entry) => entry.guid);
9322
- declarations.push({
9323
- sourcePath,
9324
- canonicalSourcePath: sourcePath.replace(/\\/g, "/"),
9325
- producer: "scriptable-pack",
9326
- packageId: meta.packageId,
9327
- projectedMeta: {
9328
- schemaVersion: meta.schemaVersion,
9329
- packageId: meta.packageId,
9330
- importer: meta.importer,
9331
- source: meta.source,
9332
- ...meta.name === void 0 ? {} : { name: meta.name },
9333
- outputs,
9334
- externalGuids
9335
- },
9336
- outputs,
9337
- externalGuids,
9338
- sourceClosure,
9339
- diagnostics: []
9340
- });
9103
+ guidToPath.set(guid, sourcePath);
9341
9104
  }
9342
- } finally {
9343
- await scriptablePackExecutorPool?.dispose();
9344
9105
  }
9345
9106
  const visited = /* @__PURE__ */ new Set();
9346
9107
  const recStack = /* @__PURE__ */ new Set();
@@ -9373,21 +9134,10 @@ async function scanInventory(roots, opts = {}) {
9373
9134
  }
9374
9135
  }
9375
9136
  }
9376
- const declarationsByPath = new Map(
9377
- declarations.map((declaration) => [declaration.sourcePath, declaration])
9378
- );
9379
- return ok4({
9380
- paths: rawPaths,
9381
- scriptablePackMeta,
9382
- declarations,
9383
- declarationsByPath,
9384
- sourceByGuid: new Map(guidToPath),
9385
- metaByGuid
9386
- });
9137
+ return ok4(rawPaths);
9387
9138
  }
9388
9139
  async function scan(roots, opts = {}) {
9389
- const inventory = await scanInventory(roots, opts);
9390
- return inventory.ok ? ok4([...inventory.value.paths]) : inventory;
9140
+ return scanValidated(roots, opts);
9391
9141
  }
9392
9142
 
9393
9143
  // src/evidence/source-inventory.ts
@@ -9819,12 +9569,9 @@ async function readJson(path, ctx) {
9819
9569
  }
9820
9570
  }
9821
9571
  function catalogRows(value) {
9822
- if (Array.isArray(value)) return value.filter(isRecord3);
9823
- if (!isRecord3(value) || !Array.isArray(value.entries)) return void 0;
9824
- return value.entries.filter(isRecord3);
9825
- }
9826
- function isRecord3(value) {
9827
- return value !== null && typeof value === "object" && !Array.isArray(value);
9572
+ if (Array.isArray(value)) return value.filter(isRecord2);
9573
+ if (!isRecord2(value) || !Array.isArray(value.entries)) return void 0;
9574
+ return value.entries.filter(isRecord2);
9828
9575
  }
9829
9576
  function packagePath(projectRoot, packageUrl) {
9830
9577
  const relative3 = packageUrl.replace(/^\/+/, "");