@forgeax/engine-import 0.1.29 → 0.1.31

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.
package/README.md CHANGED
@@ -48,6 +48,13 @@ identity. The result is a dynamic `sourceKey -> Asset` map; the bridge derives
48
48
  assets through the same registered output producers and Pack v2 finalizer used
49
49
  by ordinary imports.
50
50
 
51
+ The same map also accepts explicit `PackCookSource` rows for custom kinds.
52
+ Their `execution: 'cooked'` and `source` fields dispatch through the existing
53
+ build-time NativeCooker registry; the closed ordinary Asset producer union is
54
+ unchanged. Cooked refs, artifacts and fingerprints participate in the same
55
+ worklist, reference validation and finalizer. Staged content reads retain the
56
+ custom author source instead of pretending its metadata is a runtime asset.
57
+
51
58
  `buildScriptablePackWorklist()` is the internal clean-generation
52
59
  fixed point. Subjects are evaluated in stable order, a forward `readByGuid()`
53
60
  content miss waits for the subject that can materialize that GUID, and a pass
@@ -141,6 +148,14 @@ flowchart LR
141
148
 
142
149
  Domain producers return structured `ImportError`; the generic bridge contains no per-kind switch. `createStandardAssetOutputProducerRegistry(sceneComponents)` composes the production Scene, Material, and Mesh owners with the definition-bound scene schema. Scene refs use the ECS externalization kernel shared with runtime save, Material refs cover parent/texture/sampler GUIDs, and Mesh emits the versioned binary artifact. The fingerprint covers canonical Meta, the definition-bound scene schema, the recursive source closure, observed external evidence, authoring contract version, and registered producer versions.
143
150
 
151
+ Authored, staged and file-backed asset snapshots share the versioned
152
+ `scriptable-pack-fingerprint/2` encoding. It streams SHA-256 over ordered metadata
153
+ and typed-buffer byte ranges, including each buffer type and byte length. A large
154
+ mesh therefore does not become one JSON property per float or require a single
155
+ giant string. Subarray fingerprints include only the selected range. The encoding
156
+ change regenerates opaque build fingerprints; asset GUIDs and cooked mesh formats
157
+ are unchanged.
158
+
144
159
  `createScriptablePackStagedAssetSnapshotSource()` owns clean-build content reads. It resolves a GUID to its local source owner, lazily builds that owner inside one fixed generation, memoizes private clones and digests, and reports `pack-content-dependency-stalled` for a cycle without consulting an older fallback generation. A fallback is only an explicit prebuilt authority for GUIDs with no local owner.
145
160
 
146
161
  `createStandardAssetOutputProducerRegistry(sceneComponents)` registers the production
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scriptable-pack-fingerprint.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scriptable-pack-fingerprint.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scriptable-pack-fingerprint.unit.test.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"build-production.d.ts","sourceRoot":"","sources":["../src/build-production.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AASvE,OAAO,KAAK,EAKV,cAAc,EACd,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAkB/D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;CACtC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAAC;IAC5C,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IACzC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,QAAQ,CAAC,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,YAAY,CAAC,CAAC;IAC9E,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,KAAK,CAAC;CAC3D;AA+vBD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,cAAc,EAAE,CAAC,CAkB3B"}
1
+ {"version":3,"file":"build-production.d.ts","sourceRoot":"","sources":["../src/build-production.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AASvE,OAAO,KAAK,EAKV,cAAc,EACd,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAkB/D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;CACtC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAAC;IAC5C,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IACzC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAC1C,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,QAAQ,CAAC,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,YAAY,CAAC,CAAC;IAC9E,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,KAAK,CAAC;CAC3D;AA2vBD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,cAAc,EAAE,CAAC,CAkB3B"}
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ export { IMPORT_ERROR_HINTS, ImportError } from '@forgeax/engine-types';
3
3
  import { resolve, dirname, isAbsolute, relative } from 'path';
4
4
  import { resolveAssetSource, finalizePackageTransportSource, packageTransportRevision, catalogSourcePathFor, buildCatalogProjection, projectPackageCatalog, createRuntimePackPublication, metaPathForGuid } from '@forgeax/engine-pack/build';
5
5
  import { AssetGuid as AssetGuid$1, PackageId as PackageId$1 } from '@forgeax/engine-pack/guid';
6
- import { resolvePackParameterValues, PackageId, isValidPackSourceKey, AssetGuid, parsePackSourceJson, projectDirectPackJson, isScriptablePackAssetKind, projectScriptablePackSceneComponents, resolvePackParameterInheritance } from '@forgeax/engine-pack/source';
6
+ import { resolvePackParameterValues, PackageId, isValidPackSourceKey, isScriptablePackAssetKind, AssetGuid, parsePackSourceJson, projectDirectPackJson, projectScriptablePackSceneComponents, resolvePackParameterInheritance } from '@forgeax/engine-pack/source';
7
7
  import { loadScriptablePack } from '@forgeax/engine-pack/source-node';
8
8
  import { stat, readFile, mkdir, writeFile, rename, rm, readdir } from 'fs/promises';
9
9
  import { createAcceptedPublication, ddcOutputDigest, DdcLifecycle, DdcGenerationSession } from '@forgeax/engine-ddc';
@@ -11,12 +11,12 @@ import { deriveVertexLayoutProjection, normalizeMeshPayload } from '@forgeax/eng
11
11
  import { BUILTIN_MESH_ASSETS } from '@forgeax/engine-pack/builtin';
12
12
  import { NativeCookerRegistry } from '@forgeax/engine-pack/native-cooker';
13
13
  import { isEngineMaterial } from '@forgeax/engine-shader';
14
- import { externalizeSceneAsset } from '@forgeax/engine-scene';
15
14
  import { sha256 } from '@noble/hashes/sha2.js';
16
15
  import { bytesToHex } from '@noble/hashes/utils.js';
16
+ import { externalizeSceneAsset } from '@forgeax/engine-scene';
17
17
  import { MESH_BIN_HEADER_V4_BYTES, writeMeshBinHeader } from '@forgeax/engine-pack/mesh-bin-contract';
18
- import { createHash, randomUUID } from 'crypto';
19
18
  import { validatePack, isScriptablePackAssetKind as isScriptablePackAssetKind$1 } from '@forgeax/engine-pack';
19
+ import { createHash, randomUUID } from 'crypto';
20
20
  import { canonicalDdcJson } from '@forgeax/engine-ddc/key';
21
21
 
22
22
  // src/index.ts
@@ -45,8 +45,8 @@ async function sha256Hex(bytes2) {
45
45
  if (subtle === void 0) throw new Error("Web Crypto API is required for importer digests");
46
46
  const owned = new Uint8Array(bytes2.byteLength);
47
47
  owned.set(bytes2);
48
- const digest3 = await subtle.digest("SHA-256", owned.buffer);
49
- return Array.from(new Uint8Array(digest3), (byte) => byte.toString(16).padStart(2, "0")).join("");
48
+ const digest = await subtle.digest("SHA-256", owned.buffer);
49
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
50
50
  }
51
51
  async function artifactDigest(bytes2) {
52
52
  return `sha256:${await sha256Hex(bytes2)}`;
@@ -109,19 +109,19 @@ function finalizeImportProducts(product, inputFingerprint) {
109
109
  const products = [];
110
110
  for (const asset of product.assets) {
111
111
  const artifacts = await artifactDescriptors(asset.artifacts);
112
- const digest3 = await productDigest(asset, artifacts);
112
+ const digest = await productDigest(asset, artifacts);
113
113
  products.push({
114
114
  guid: asset.guid,
115
115
  payload: asset.payload,
116
116
  refs: asset.refs.map((ref2) => ref2.guid),
117
117
  artifacts,
118
- digest: digest3,
118
+ digest,
119
119
  receipt: {
120
120
  guid: asset.guid,
121
121
  origin: "sourceMeta",
122
122
  status: "succeeded",
123
123
  inputFingerprint,
124
- outputDigest: digest3
124
+ outputDigest: digest
125
125
  }
126
126
  });
127
127
  }
@@ -779,6 +779,48 @@ function projectImportProductForBuild(product) {
779
779
  }))
780
780
  };
781
781
  }
782
+ function scriptablePackFingerprint(value) {
783
+ const hash = sha256.create();
784
+ const encoder = new TextEncoder();
785
+ const text = (part) => {
786
+ hash.update(encoder.encode(part));
787
+ };
788
+ const binary = (type, bytes2) => {
789
+ text(`\0${type}:${bytes2.byteLength}:`);
790
+ hash.update(bytes2);
791
+ text("\0");
792
+ };
793
+ const visit = (item) => {
794
+ if (ArrayBuffer.isView(item)) {
795
+ binary(item.constructor.name, new Uint8Array(item.buffer, item.byteOffset, item.byteLength));
796
+ } else if (item instanceof ArrayBuffer) {
797
+ binary("ArrayBuffer", new Uint8Array(item));
798
+ } else if (Array.isArray(item)) {
799
+ text("[");
800
+ for (let i = 0; i < item.length; i++) {
801
+ if (i) text(",");
802
+ visit(item[i]);
803
+ }
804
+ text("]");
805
+ } else if (item !== null && typeof item === "object") {
806
+ const object = item;
807
+ text("{");
808
+ let first = true;
809
+ for (const key of Object.keys(object).sort()) {
810
+ if (!first) text(",");
811
+ first = false;
812
+ text(`${JSON.stringify(key)}:`);
813
+ visit(object[key]);
814
+ }
815
+ text("}");
816
+ } else {
817
+ text(JSON.stringify(item) ?? "null");
818
+ }
819
+ };
820
+ text("scriptable-pack-fingerprint/2:");
821
+ visit(value);
822
+ return `sha256:${bytesToHex(hash.digest())}`;
823
+ }
782
824
  function failure(sourceKey, expected, actual) {
783
825
  return {
784
826
  code: "mesh-bin-payload-invalid",
@@ -1473,21 +1515,6 @@ function needsMaterialCook(asset) {
1473
1515
  function clone(value) {
1474
1516
  return structuredClone(value);
1475
1517
  }
1476
- function stable(value) {
1477
- if (value instanceof Uint8Array) return JSON.stringify(Array.from(value));
1478
- if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`;
1479
- if (value !== null && typeof value === "object") {
1480
- const object = value;
1481
- return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stable(object[key])}`).join(",")}}`;
1482
- }
1483
- return JSON.stringify(value) ?? "null";
1484
- }
1485
- async function digest(value) {
1486
- const crypto = globalThis.crypto?.subtle;
1487
- if (crypto === void 0) throw new Error("Web Crypto API is required for Pack fingerprints");
1488
- const bytes2 = await crypto.digest("SHA-256", new TextEncoder().encode(stable(value)));
1489
- return `sha256:${Array.from(new Uint8Array(bytes2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
1490
- }
1491
1518
  function observedReader(source) {
1492
1519
  const reads = /* @__PURE__ */ new Map();
1493
1520
  const reader = {
@@ -1694,14 +1721,25 @@ async function buildScriptablePack(options) {
1694
1721
  const imported = [];
1695
1722
  const stagedOutputs = [];
1696
1723
  const localGuids = /* @__PURE__ */ new Set();
1697
- const materialCookerRegistry = new NativeCookerRegistry();
1698
- for (const cooker of options.cookers ?? []) materialCookerRegistry.register(cooker);
1724
+ const cookerRegistry = new NativeCookerRegistry();
1725
+ for (const cooker of options.cookers ?? []) cookerRegistry.register(cooker);
1699
1726
  const nativeFingerprints = /* @__PURE__ */ new Map();
1700
1727
  for (const sourceKey of Object.keys(built.value).sort()) {
1701
1728
  if (!isValidPackSourceKey(sourceKey))
1702
1729
  return err(sourceKeyFailure(options.sourcePath, sourceKey));
1703
1730
  const asset = built.value[sourceKey];
1704
- if (!isAsset(asset)) {
1731
+ const customSource = record(asset) && asset.execution === "cooked";
1732
+ if (customSource && (typeof asset.kind !== "string" || asset.kind.trim().length === 0 || isScriptablePackAssetKind(asset.kind) || !("source" in asset) || Object.keys(asset).some((key) => !["kind", "execution", "source"].includes(key)))) {
1733
+ return err(
1734
+ outputValueError(
1735
+ options.sourcePath,
1736
+ sourceKey,
1737
+ "a custom kind with only execution: cooked and source; ordinary Assets use their standard producers",
1738
+ asset
1739
+ )
1740
+ );
1741
+ }
1742
+ if (!customSource && !isAsset(asset)) {
1705
1743
  return err(
1706
1744
  outputValueError(
1707
1745
  options.sourcePath,
@@ -1722,6 +1760,46 @@ async function buildScriptablePack(options) {
1722
1760
  });
1723
1761
  }
1724
1762
  localGuids.add(normalizedGuid);
1763
+ if (customSource) {
1764
+ const cooked = await cookerRegistry.runDraft(asset.kind, {
1765
+ guid,
1766
+ sourceKey,
1767
+ sourcePath: options.sourcePath,
1768
+ source: asset.source,
1769
+ refs: []
1770
+ });
1771
+ if (!cooked.ok) return err(cooked.error);
1772
+ if (cooked.value.guid.toLowerCase() !== normalizedGuid)
1773
+ return err({
1774
+ code: "pack-source-output-invalid",
1775
+ expected: "the custom cooker to preserve the derived AssetGuid",
1776
+ hint: "remove cooker-owned identity generation and retain the host GUID",
1777
+ detail: {
1778
+ sourcePath: options.sourcePath,
1779
+ sourceKey,
1780
+ expectedGuid: guid,
1781
+ actualGuid: cooked.value.guid
1782
+ }
1783
+ });
1784
+ const product3 = {
1785
+ payload: cooked.value.payload,
1786
+ refs: cooked.value.refs.map((guid2) => ({ guid: guid2 })),
1787
+ artifacts: cooked.value.artifacts
1788
+ };
1789
+ const invalid = productError(options.sourcePath, sourceKey, { kind: asset.kind }, product3);
1790
+ if (invalid !== void 0) return err(invalid);
1791
+ imported.push({ guid, kind: asset.kind, ...product3 });
1792
+ nativeFingerprints.set(sourceKey, cooked.value.inputFingerprint);
1793
+ stagedOutputs.push({
1794
+ guid: AssetGuid.derive(subjectPackageId, sourceKey),
1795
+ sourceKey,
1796
+ asset: clone(asset),
1797
+ digest: await scriptablePackFingerprint(asset)
1798
+ });
1799
+ continue;
1800
+ }
1801
+ if (!isAsset(asset))
1802
+ return err(outputValueError(options.sourcePath, sourceKey, "an ordinary Asset", asset));
1725
1803
  const producer = options.outputs.get(asset.kind);
1726
1804
  if (producer === void 0) {
1727
1805
  return err(
@@ -1775,8 +1853,8 @@ async function buildScriptablePack(options) {
1775
1853
  let payload = product2.payload;
1776
1854
  let artifacts2 = product2.artifacts;
1777
1855
  let refs2 = product2.refs;
1778
- if (needsMaterialCook(asset) && materialCookerRegistry.get("material") !== void 0) {
1779
- const cooked = await materialCookerRegistry.runDraft("material", {
1856
+ if (needsMaterialCook(asset) && cookerRegistry.get("material") !== void 0) {
1857
+ const cooked = await cookerRegistry.runDraft("material", {
1780
1858
  guid,
1781
1859
  source: asset,
1782
1860
  sourceKey,
@@ -1857,7 +1935,7 @@ async function buildScriptablePack(options) {
1857
1935
  guid: AssetGuid.derive(subjectPackageId, sourceKey),
1858
1936
  sourceKey,
1859
1937
  asset: clone(asset),
1860
- digest: await digest(asset)
1938
+ digest: await scriptablePackFingerprint(asset)
1861
1939
  });
1862
1940
  }
1863
1941
  const referenced = /* @__PURE__ */ new Set();
@@ -1882,7 +1960,7 @@ async function buildScriptablePack(options) {
1882
1960
  digest: read.digest
1883
1961
  })
1884
1962
  );
1885
- const authoredInputFingerprint = await digest({
1963
+ const authoredInputFingerprint = await scriptablePackFingerprint({
1886
1964
  packageId: PackageId.format(subjectPackageId),
1887
1965
  sourcePath: options.sourcePath,
1888
1966
  sourceClosure: options.sourceClosure ?? [],
@@ -1895,7 +1973,7 @@ async function buildScriptablePack(options) {
1895
1973
  authoringContractVersion: options.authoringContractVersion ?? "scriptable-pack/1",
1896
1974
  producerVersions: options.outputs.versions()
1897
1975
  });
1898
- const inputFingerprint = nativeFingerprints.size === 0 ? authoredInputFingerprint : await digest({
1976
+ const inputFingerprint = nativeFingerprints.size === 0 ? authoredInputFingerprint : await scriptablePackFingerprint({
1899
1977
  sourceRevision: authoredInputFingerprint,
1900
1978
  nativeCookers: [...nativeFingerprints.entries()].sort(
1901
1979
  ([left], [right]) => left.localeCompare(right)
@@ -2848,7 +2926,7 @@ async function produceScriptablePackProducts(options) {
2848
2926
  }
2849
2927
  return ok(prepared);
2850
2928
  }
2851
- async function scriptablePackResourceRevision(displaySourcePath, digest3, sourceClosure) {
2929
+ async function scriptablePackResourceRevision(displaySourcePath, digest, sourceClosure) {
2852
2930
  const mtimes = await Promise.all(
2853
2931
  sourceClosure.map(async (entry) => {
2854
2932
  try {
@@ -2862,7 +2940,7 @@ async function scriptablePackResourceRevision(displaySourcePath, digest3, source
2862
2940
  })
2863
2941
  );
2864
2942
  const observedAt = mtimes.length === 0 ? 0 : Math.trunc(Math.max(...mtimes));
2865
- return { digest: digest3, observedAt, rootId: displaySourcePath };
2943
+ return { digest, observedAt, rootId: displaySourcePath };
2866
2944
  }
2867
2945
  function normalizeCatalogPath(path) {
2868
2946
  return path.replaceAll("\\", "/").replace(/^\.\//, "");
@@ -2895,16 +2973,11 @@ function runtimePublicationFor(context, input) {
2895
2973
  ...input.digest === void 0 ? {} : { digest: input.digest },
2896
2974
  ...input.inputFingerprint === void 0 ? {} : { inputFingerprint: input.inputFingerprint },
2897
2975
  ...input.outputs === void 0 ? {} : { outputs: input.outputs },
2976
+ ...input.sourceKeys === void 0 ? {} : { sourceKeys: input.sourceKeys },
2898
2977
  ...input.externalEvidence === void 0 ? {} : { externalEvidence: input.externalEvidence },
2899
2978
  generation: context.runtimeBinding?.generation ?? context.generation
2900
2979
  };
2901
- if (input.sourceKeys === void 0) return createRuntimePackPublication(publicationInput);
2902
- const derived = createRuntimePackPublication(publicationInput);
2903
- const outputs = derived.publication.outputs.map((output) => ({
2904
- ...output,
2905
- sourceKey: input.sourceKeys?.get(output.guid.toLowerCase()) ?? output.sourceKey
2906
- }));
2907
- return createRuntimePackPublication({ ...publicationInput, outputs });
2980
+ return createRuntimePackPublication(publicationInput);
2908
2981
  }
2909
2982
  function sourceKeysFor(declarations) {
2910
2983
  return new Map(
@@ -3303,6 +3376,7 @@ async function emitAuthoredPack(work, guidSeen, entry, availableGuids) {
3303
3376
  };
3304
3377
  const runtimePublication = runtimePublicationFor(work.context, {
3305
3378
  pack: authoredPack,
3379
+ sourceKeys: sourceKeysFor(legacy.assets),
3306
3380
  sourcePath: entry.sourcePath,
3307
3381
  sourceRevision: declaration.sourceRevision,
3308
3382
  packageUrl: prepared.finalized?.packageUrl ?? `${work.context.basePrefix === "/" ? "" : work.context.basePrefix}/assets/${outputGuid}.pack.json`,
@@ -3885,25 +3959,6 @@ var ImporterRegistry = class {
3885
3959
  function isRecord2(value) {
3886
3960
  return value !== null && typeof value === "object" && !Array.isArray(value);
3887
3961
  }
3888
- function stable2(value) {
3889
- if (value instanceof ArrayBuffer) {
3890
- return `ArrayBuffer:${JSON.stringify(Array.from(new Uint8Array(value)))}`;
3891
- }
3892
- if (ArrayBuffer.isView(value)) {
3893
- return `${value.constructor.name}:${JSON.stringify(
3894
- Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength))
3895
- )}`;
3896
- }
3897
- if (Array.isArray(value)) return `[${value.map(stable2).join(",")}]`;
3898
- if (value !== null && typeof value === "object") {
3899
- const record2 = value;
3900
- return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stable2(record2[key])}`).join(",")}}`;
3901
- }
3902
- return JSON.stringify(value) ?? "null";
3903
- }
3904
- function digest2(value) {
3905
- return `sha256:${createHash("sha256").update(stable2(value)).digest("hex")}`;
3906
- }
3907
3962
  function generationFromDigest(value) {
3908
3963
  const parsed = Number.parseInt(value.slice("sha256:".length, "sha256:".length + 8), 16);
3909
3964
  return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 1;
@@ -4006,7 +4061,7 @@ function assetFromRow(path, row) {
4006
4061
  });
4007
4062
  }
4008
4063
  const asset = { ...row.payload, kind: row.kind };
4009
- return ok({ asset, digest: digest2(asset) });
4064
+ return ok({ asset, digest: scriptablePackFingerprint(asset) });
4010
4065
  }
4011
4066
  async function indexPackFiles(assetRoots) {
4012
4067
  const files = await collectPackFiles(assetRoots);
@@ -4067,9 +4122,7 @@ async function indexPackFiles(assetRoots) {
4067
4122
  byGuid.set(key, asset.value);
4068
4123
  }
4069
4124
  }
4070
- const sourceDigest = digest2(
4071
- [...documents].sort((left, right) => stable2(left).localeCompare(stable2(right)))
4072
- );
4125
+ const sourceDigest = scriptablePackFingerprint(documents.map(scriptablePackFingerprint).sort());
4073
4126
  return ok({
4074
4127
  generation: generationFromDigest(sourceDigest),
4075
4128
  assets: byGuid
@@ -4099,22 +4152,6 @@ function createScriptablePackFileAssetSnapshotSource(options) {
4099
4152
  }
4100
4153
  };
4101
4154
  }
4102
- function stable3(value) {
4103
- if (ArrayBuffer.isView(value)) {
4104
- return `${value.constructor.name}:${JSON.stringify(Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength)))}`;
4105
- }
4106
- if (Array.isArray(value)) return `[${value.map(stable3).join(",")}]`;
4107
- if (value !== null && typeof value === "object") {
4108
- const record2 = value;
4109
- return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stable3(record2[key])}`).join(",")}}`;
4110
- }
4111
- return JSON.stringify(value) ?? "null";
4112
- }
4113
- async function assetDigest(asset) {
4114
- const bytes2 = new TextEncoder().encode(stable3(asset));
4115
- const digest3 = await globalThis.crypto.subtle.digest("SHA-256", bytes2);
4116
- return `sha256:${Array.from(new Uint8Array(digest3), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
4117
- }
4118
4155
  function cycleError(stack, owner, guid) {
4119
4156
  const cycleStart = stack.indexOf(owner);
4120
4157
  const cycle = [...stack.slice(cycleStart), owner];
@@ -4192,7 +4229,7 @@ function createScriptablePackStagedAssetSnapshotSource(options) {
4192
4229
  next.set(outputGuid, {
4193
4230
  asset: structuredClone(output.asset),
4194
4231
  generation: options.generation,
4195
- digest: output.digest ?? await assetDigest(output.asset)
4232
+ digest: output.digest ?? await scriptablePackFingerprint(output.asset)
4196
4233
  });
4197
4234
  }
4198
4235
  for (const declared of owner.guids) {
@@ -4606,8 +4643,8 @@ function validatePublicationArtifactClosure(input) {
4606
4643
  return ok(publicationArtifacts(input.transport));
4607
4644
  }
4608
4645
  function projectImportPublication(input, head, observedAt) {
4609
- const digest3 = head.currentKey ?? input.desiredKey;
4610
- const revision = { digest: digest3, observedAt, rootId: input.root };
4646
+ const digest = head.currentKey ?? input.desiredKey;
4647
+ const revision = { digest, observedAt, rootId: input.root };
4611
4648
  const published = new Set(input.publishedGuids.map((guid) => guid.toLowerCase()));
4612
4649
  const catalog = input.nextCatalog.map((row) => {
4613
4650
  if (!published.has(row.guid.toLowerCase())) return row;