@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 +15 -0
- package/dist/__tests__/scriptable-pack-fingerprint.unit.test.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-fingerprint.unit.test.d.ts.map +1 -0
- package/dist/build-production.d.ts.map +1 -1
- package/dist/index.mjs +119 -82
- package/dist/index.mjs.map +1 -1
- package/dist/scriptable-pack-build.d.ts.map +1 -1
- package/dist/scriptable-pack-file-snapshot.d.ts.map +1 -1
- package/dist/scriptable-pack-fingerprint.d.ts +3 -0
- package/dist/scriptable-pack-fingerprint.d.ts.map +1 -0
- package/dist/scriptable-pack-staged-snapshot.d.ts.map +1 -1
- package/dist/scriptable-pack.d.ts +3 -3
- package/dist/scriptable-pack.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/scriptable-pack-build.unit.test.ts +129 -0
- package/src/__tests__/scriptable-pack-fingerprint.unit.test.ts +65 -0
- package/src/build-production.ts +3 -7
- package/src/scriptable-pack-build.ts +74 -32
- package/src/scriptable-pack-file-snapshot.ts +2 -28
- package/src/scriptable-pack-fingerprint.ts +48 -0
- package/src/scriptable-pack-staged-snapshot.ts +2 -22
- package/src/scriptable-pack.ts +3 -2
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 @@
|
|
|
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;
|
|
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,
|
|
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
|
|
49
|
-
return Array.from(new Uint8Array(
|
|
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
|
|
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
|
|
118
|
+
digest,
|
|
119
119
|
receipt: {
|
|
120
120
|
guid: asset.guid,
|
|
121
121
|
origin: "sourceMeta",
|
|
122
122
|
status: "succeeded",
|
|
123
123
|
inputFingerprint,
|
|
124
|
-
outputDigest:
|
|
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
|
|
1698
|
-
for (const cooker of options.cookers ?? [])
|
|
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
|
-
|
|
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) &&
|
|
1779
|
-
const cooked = await
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
4610
|
-
const revision = { digest
|
|
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;
|