@forgeax/engine-pack 0.1.28 → 0.1.29

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 (41) hide show
  1. package/README.md +17 -5
  2. package/dist/build.mjs +34 -51
  3. package/dist/build.mjs.map +1 -1
  4. package/dist/cli-asset.mjs +21 -12
  5. package/dist/cli-asset.mjs.map +1 -1
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/inventory/declaration.d.ts +1 -1
  8. package/dist/inventory/declaration.d.ts.map +1 -1
  9. package/dist/inventory/sync.d.ts.map +1 -1
  10. package/dist/native-cooker-registry.d.ts +1 -0
  11. package/dist/native-cooker-registry.d.ts.map +1 -1
  12. package/dist/native-cooker.mjs.map +1 -1
  13. package/dist/pack-authoring-node.mjs +21 -12
  14. package/dist/pack-authoring-node.mjs.map +1 -1
  15. package/dist/runtime.mjs.map +1 -1
  16. package/dist/scanner.mjs +21 -12
  17. package/dist/scanner.mjs.map +1 -1
  18. package/dist/schema-compiled.d.ts.map +1 -1
  19. package/dist/schema.mjs +40 -62
  20. package/dist/schema.mjs.map +1 -1
  21. package/dist/scriptable-pack-node.d.ts.map +1 -1
  22. package/dist/scriptable-pack-node.mjs +11 -3
  23. package/dist/scriptable-pack-node.mjs.map +1 -1
  24. package/dist/scriptable-pack-worker.mjs +5 -1
  25. package/dist/scriptable-pack-worker.mjs.map +1 -1
  26. package/package.json +2 -2
  27. package/src/__tests__/inventory-schema.test.ts +10 -10
  28. package/src/__tests__/pack-authoring.unit.test.ts +2 -4
  29. package/src/__tests__/pack.unit.test.ts +86 -124
  30. package/src/__tests__/scanner-instance-cycle.test.ts +92 -0
  31. package/src/__tests__/scanner-inventory.contract.test.ts +2 -2
  32. package/src/__tests__/scriptable-pack-diagnostic.integration.test.ts +45 -0
  33. package/src/inventory/binding.ts +3 -3
  34. package/src/inventory/declaration.ts +10 -48
  35. package/src/inventory/sync.ts +3 -2
  36. package/src/native-cooker-registry.ts +1 -0
  37. package/src/scanner.ts +28 -28
  38. package/src/schema-compiled.ts +40 -79
  39. package/src/scriptable-pack-node.ts +11 -3
  40. package/src/scriptable-pack-worker.ts +8 -1
  41. package/src/__tests__/scanner-mount-cycle.test.ts +0 -232
package/README.md CHANGED
@@ -37,11 +37,22 @@ export default definePack({
37
37
  build: ({ packageId: subjectId }) =>
38
38
  ok({
39
39
  'mesh/main': { kind: 'mesh', materialSlots: [] },
40
+ 'scene/hero': {
41
+ kind: 'scene',
42
+ entities: { body: { components: {} } },
43
+ },
40
44
  'scene/main': {
41
45
  kind: 'scene',
42
- entities: [],
43
- mounts: [],
44
- mesh: AssetGuid.format(AssetGuid.derive(subjectId, 'mesh/main')),
46
+ entities: {
47
+ root: { components: {} },
48
+ hero: {
49
+ components: {},
50
+ instance: {
51
+ source: AssetGuid.format(AssetGuid.derive(subjectId, 'scene/hero')),
52
+ overrides: [{ target: ['body'], components: {} }],
53
+ },
54
+ },
55
+ },
45
56
  },
46
57
  }),
47
58
  });
@@ -201,9 +212,10 @@ Pack owns the offline half of the GUID evidence chain: `source inventory -> cata
201
212
 
202
213
  The catalog is a locator, not proof. `lookup/verify --guid --project --catalog --json` joins the source meta or authored pack, the catalog row, the receipt, and the package descriptors. Both commands emit one JSON record on stdout or one structured `{code, expected, hint, detail}` record on stderr; there is no runtime or WebSocket dependency.
203
214
 
204
- ## VFX Pack v2 migration
215
+ ## VFX Program v3 in Pack v2
205
216
 
206
- VFX source v2 is cooked in one atomic producer step. The executable contract is
217
+ VFX source v3 is cooked in one atomic producer step and stored in the ordinary
218
+ Pack v2 envelope. The executable contract is
207
219
  `scripts/asset-cook-contract.mjs`; a package-local scripts path is not valid.
208
220
  The cook publishes the Pack payload and
209
221
  `particle-effect/program.json` with the same source fingerprint. Runtime loads
package/dist/build.mjs CHANGED
@@ -9061,9 +9061,17 @@ var WorkerScriptablePackExecutor = class {
9061
9061
  }
9062
9062
  };
9063
9063
  worker.on("message", onMessage);
9064
- worker.once("error", rejectLoad);
9064
+ const fail = (error) => {
9065
+ rejectLoad(error);
9066
+ const active = this.build;
9067
+ this.build = void 0;
9068
+ active?.reject(error);
9069
+ void this.dispose("failure");
9070
+ };
9071
+ worker.once("error", fail);
9065
9072
  worker.once("exit", (code) => {
9066
- if (code !== 0) rejectLoad(new Error(`ScriptablePack worker exited with code ${code}`));
9073
+ if (this.disposal !== void 0) return;
9074
+ fail(new Error(`ScriptablePack worker exited with code ${code}`));
9067
9075
  });
9068
9076
  });
9069
9077
  }
@@ -9298,16 +9306,17 @@ function makePackError(code, detail) {
9298
9306
  detail
9299
9307
  });
9300
9308
  }
9301
- function* extractMountSourceGuids(asset) {
9309
+ function* extractInstanceSourceGuids(asset) {
9302
9310
  if (asset.kind !== "scene") return;
9303
9311
  const payload = asset.payload;
9304
- if (!payload || !Array.isArray(payload.mounts)) return;
9305
- for (const rawMount of payload.mounts) {
9306
- const mount = rawMount;
9307
- const idx = mount.source;
9308
- if (typeof idx !== "number" || !Number.isInteger(idx)) continue;
9309
- if (idx < 0 || idx >= asset.refs.length) continue;
9310
- const resolved = asset.refs[idx];
9312
+ if (!payload || payload.entities === null || typeof payload.entities !== "object" || Array.isArray(payload.entities))
9313
+ return;
9314
+ for (const rawEntity of Object.values(payload.entities)) {
9315
+ if (rawEntity === null || typeof rawEntity !== "object" || Array.isArray(rawEntity)) continue;
9316
+ const instance = rawEntity.instance;
9317
+ if (instance === null || typeof instance !== "object" || Array.isArray(instance)) continue;
9318
+ const source = instance.source;
9319
+ const resolved = typeof source === "number" && Number.isInteger(source) ? asset.refs[source] : typeof source === "string" ? source : void 0;
9311
9320
  if (typeof resolved !== "string") continue;
9312
9321
  yield resolved.toLowerCase();
9313
9322
  }
@@ -9425,7 +9434,7 @@ async function scanValidated(roots, opts = {}, capture) {
9425
9434
  guidToPath.set(normalizedGuid, packPath);
9426
9435
  packRefs.set(normalizedGuid, [
9427
9436
  ...asset.refs.map((ref) => ref.toLowerCase()),
9428
- ...extractMountSourceGuids(asset)
9437
+ ...extractInstanceSourceGuids(asset)
9429
9438
  ]);
9430
9439
  }
9431
9440
  }
@@ -9529,7 +9538,7 @@ async function scanValidated(roots, opts = {}, capture) {
9529
9538
  guidToPath.set(normalizedGuid, packPath);
9530
9539
  packRefs.set(normalizedGuid, [
9531
9540
  ...asset.refs.map((ref) => ref.toLowerCase()),
9532
- ...extractMountSourceGuids(asset)
9541
+ ...extractInstanceSourceGuids(asset)
9533
9542
  ]);
9534
9543
  }
9535
9544
  capture?.declarations.set(packPath, {
@@ -10714,9 +10723,9 @@ function projectAssetRefs(inventory) {
10714
10723
  }
10715
10724
  function projectSceneEntityRefs(inventory) {
10716
10725
  return inventory.declarations.flatMap(
10717
- (row) => row.sceneBindings === void 0 ? [] : row.sceneBindings.map((bindingKey) => ({
10726
+ (row) => row.sceneEntityKeys === void 0 ? [] : row.sceneEntityKeys.map((address) => ({
10718
10727
  sceneSourceKey: row.sourceKey,
10719
- bindingKey
10728
+ address
10720
10729
  }))
10721
10730
  );
10722
10731
  }
@@ -10776,49 +10785,23 @@ function validateAuthorInventory(value) {
10776
10785
  { guid, sourceKey: sourceKey2 }
10777
10786
  );
10778
10787
  }
10779
- if (row.kind === "scene") {
10780
- const payload = row.payload;
10781
- const payloadRecord = typeof payload === "object" && payload !== null ? payload : void 0;
10782
- const entities = payloadRecord !== void 0 && Array.isArray(payloadRecord.entities) ? payloadRecord.entities : [];
10783
- const bindings = /* @__PURE__ */ new Set();
10784
- for (const entity of entities) {
10785
- const bindingKey = typeof entity === "object" && entity !== null && typeof entity.bindingKey === "string" ? entity.bindingKey : void 0;
10786
- if (bindingKey !== void 0 && bindingKey.length === 0) {
10787
- return failure2(
10788
- "inventory-scene-binding-missing",
10789
- "each declared scene bindingKey is non-empty",
10790
- "remove the empty bindingKey or declare a stable key in the scene producer",
10791
- { sourceKey: sourceKey2 }
10792
- );
10793
- }
10794
- if (bindingKey === void 0) continue;
10795
- if (bindings.has(bindingKey)) {
10796
- return failure2(
10797
- "inventory-scene-binding-duplicate",
10798
- "bindingKey values are unique within one scene",
10799
- "rename the duplicate bindingKey in the scene producer",
10800
- { sourceKey: sourceKey2 }
10801
- );
10802
- }
10803
- bindings.add(bindingKey);
10804
- }
10805
- }
10806
10788
  guids.add(normalizedGuid);
10807
10789
  sourceKeys.add(sourceKey2);
10808
- const sceneBindings = row.kind === "scene" && typeof row.payload === "object" && row.payload !== null ? row.payload.entities?.flatMap(
10809
- (entity) => {
10810
- if (typeof entity !== "object" || entity === null) return [];
10811
- const key = entity.bindingKey;
10812
- return typeof key === "string" && key.length > 0 ? [key] : [];
10813
- }
10814
- ) : void 0;
10790
+ const sceneEntityKeys = (() => {
10791
+ if (row.kind !== "scene" || typeof row.payload !== "object" || row.payload === null)
10792
+ return void 0;
10793
+ const entities = row.payload.entities;
10794
+ if (entities === null || typeof entities !== "object" || Array.isArray(entities))
10795
+ return void 0;
10796
+ return Object.keys(entities);
10797
+ })();
10815
10798
  declarations.push({
10816
10799
  guid,
10817
10800
  sourceKey: sourceKey2,
10818
10801
  kind: typeof row.kind === "string" ? row.kind : "unknown",
10819
10802
  payload: typeof row.payload === "object" && row.payload !== null ? row.payload : {},
10820
10803
  refs: Array.isArray(row.refs) ? row.refs.filter((ref) => typeof ref === "string") : [],
10821
- ...sceneBindings === void 0 ? {} : { sceneBindings }
10804
+ ...sceneEntityKeys === void 0 ? {} : { sceneEntityKeys }
10822
10805
  });
10823
10806
  }
10824
10807
  return ok({ declarations });
@@ -10827,7 +10810,7 @@ function validateAuthorInventory(value) {
10827
10810
  // src/inventory/sync.ts
10828
10811
  function inventoryDigest(inventory) {
10829
10812
  return inventory.declarations.map(
10830
- (row) => `${row.guid}\0${row.sourceKey}\0${row.kind}\0${row.sceneBindings?.join("\0") ?? ""}`
10813
+ (row) => `${row.guid}\0${row.sourceKey}\0${row.kind}\0${row.sceneEntityKeys?.join("\0") ?? ""}`
10831
10814
  ).sort().join("\n");
10832
10815
  }
10833
10816
  function syncAuthorInventory(inventory) {
@@ -10835,7 +10818,7 @@ function syncAuthorInventory(inventory) {
10835
10818
  declarations: inventory.declarations.map((row) => ({
10836
10819
  ...row,
10837
10820
  refs: [...row.refs],
10838
- ...row.sceneBindings === void 0 ? {} : { sceneBindings: [...row.sceneBindings] }
10821
+ ...row.sceneEntityKeys === void 0 ? {} : { sceneEntityKeys: [...row.sceneEntityKeys] }
10839
10822
  }))
10840
10823
  };
10841
10824
  }