@forgeax/engine-import 0.1.21 → 0.1.24
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 +91 -3
- package/dist/__tests__/ies-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/ies-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ies-producer.unit.test.d.ts +2 -0
- package/dist/__tests__/ies-producer.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-lod-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-lod-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-lod-reimport.integration.test.d.ts +2 -0
- package/dist/__tests__/mesh-lod-reimport.integration.test.d.ts.map +1 -0
- package/dist/__tests__/scriptable-pack-build.unit.test.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-build.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scriptable-pack-file-snapshot.unit.test.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-file-snapshot.unit.test.d.ts.map +1 -0
- package/dist/__tests__/source-package-publication-lod.integration.test.d.ts +2 -0
- package/dist/__tests__/source-package-publication-lod.integration.test.d.ts.map +1 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.mjs +230 -3
- package/dist/browser.mjs.map +1 -1
- package/dist/build-production.d.ts +1 -8
- package/dist/build-production.d.ts.map +1 -1
- package/dist/ies/ies-importer.d.ts +4 -0
- package/dist/ies/ies-importer.d.ts.map +1 -0
- package/dist/ies/parse-lm63.d.ts +13 -0
- package/dist/ies/parse-lm63.d.ts.map +1 -0
- package/dist/ies/resample-type-c.d.ts +4 -0
- package/dist/ies/resample-type-c.d.ts.map +1 -0
- package/dist/import-runner.d.ts.map +1 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +2850 -1157
- package/dist/index.mjs.map +1 -1
- package/dist/mesh-bin.d.ts.map +1 -1
- package/dist/mesh-bin.mjs +29 -1
- package/dist/mesh-bin.mjs.map +1 -1
- package/dist/mesh-lod.d.ts +60 -0
- package/dist/mesh-lod.d.ts.map +1 -0
- package/dist/scriptable-pack-build.d.ts +68 -0
- package/dist/scriptable-pack-build.d.ts.map +1 -0
- package/dist/scriptable-pack-file-snapshot.d.ts +71 -0
- package/dist/scriptable-pack-file-snapshot.d.ts.map +1 -0
- package/dist/scriptable-pack-host.d.ts +68 -37
- package/dist/scriptable-pack-host.d.ts.map +1 -1
- package/dist/scriptable-pack-output-producers.d.ts +1 -0
- package/dist/scriptable-pack-output-producers.d.ts.map +1 -1
- package/dist/scriptable-pack-staged-snapshot.d.ts +2 -2
- package/dist/scriptable-pack-staged-snapshot.d.ts.map +1 -1
- package/dist/scriptable-pack.d.ts +15 -27
- package/dist/scriptable-pack.d.ts.map +1 -1
- package/dist/source-package-errors.d.ts.map +1 -1
- package/dist/source-package-publication.d.ts +7 -0
- package/dist/source-package-publication.d.ts.map +1 -1
- package/package.json +8 -7
- package/src/__tests__/ies-contract.unit.test.ts +31 -0
- package/src/__tests__/ies-producer.unit.test.ts +104 -0
- package/src/__tests__/mesh-bin.test.ts +69 -0
- package/src/__tests__/mesh-lod-contract.unit.test.ts +92 -0
- package/src/__tests__/mesh-lod-reimport.integration.test.ts +15 -0
- package/src/__tests__/scriptable-pack-build.unit.test.ts +267 -0
- package/src/__tests__/scriptable-pack-file-snapshot.unit.test.ts +177 -0
- package/src/__tests__/scriptable-pack-host.unit.test.ts +196 -4
- package/src/__tests__/scriptable-pack-production-producers.unit.test.ts +2 -0
- package/src/__tests__/scriptable-pack-staged-snapshot.unit.test.ts +43 -12
- package/src/__tests__/source-package-publication-lod.integration.test.ts +29 -0
- package/src/__tests__/source-package-publication.integration.test.ts +167 -1
- package/src/browser.ts +5 -0
- package/src/build-production.ts +491 -140
- package/src/ies/ies-importer.ts +126 -0
- package/src/ies/parse-lm63.ts +98 -0
- package/src/ies/resample-type-c.ts +108 -0
- package/src/import-runner.ts +58 -0
- package/src/index.ts +47 -16
- package/src/mesh-bin.ts +38 -0
- package/src/mesh-lod.ts +265 -0
- package/src/scriptable-pack-build.ts +725 -0
- package/src/scriptable-pack-file-snapshot.ts +346 -0
- package/src/scriptable-pack-host.ts +785 -340
- package/src/scriptable-pack-output-producers.ts +55 -0
- package/src/scriptable-pack-staged-snapshot.ts +12 -11
- package/src/scriptable-pack.ts +18 -486
- package/src/source-package-errors.ts +6 -0
- package/src/source-package-publication.ts +273 -11
- package/dist/.tsbuildinfo +0 -1
- package/dist/__tests__/scriptable-pack-product.contract.test.d.ts +0 -2
- package/dist/__tests__/scriptable-pack-product.contract.test.d.ts.map +0 -1
- package/dist/__tests__/scriptable-pack.integration.test.d.ts +0 -2
- package/dist/__tests__/scriptable-pack.integration.test.d.ts.map +0 -1
- package/dist/scriptable-source-package.d.ts +0 -14
- package/dist/scriptable-source-package.d.ts.map +0 -1
- package/src/__tests__/scriptable-pack-product.contract.test.ts +0 -46
- package/src/__tests__/scriptable-pack.integration.test.ts +0 -435
- package/src/scriptable-source-package.ts +0 -88
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import { ok, validateSourceOverrideMap, ImportError, IMPORT_ERROR_HINTS, canonicalizeSourceOverrides,
|
|
1
|
+
import { ok, err, validateSourceOverrideMap, ImportError, IMPORT_ERROR_HINTS, canonicalizeSourceOverrides, AssetError, IES_PROFILE_HEIGHT, IES_PROFILE_WIDTH, IES_PROFILE_BYTE_LENGTH, MATERIAL_TEXTURE_SLOTS, deriveTextureLayout } from '@forgeax/engine-types';
|
|
2
2
|
export { IMPORT_ERROR_HINTS, ImportError } from '@forgeax/engine-types';
|
|
3
|
-
import { resolve, isAbsolute, relative
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { resolve, dirname, isAbsolute, relative } from 'path';
|
|
4
|
+
import { resolveAssetSource, finalizePackageTransportSource, packageTransportRevision, catalogSourcePathFor, buildCatalogProjection, projectPackageCatalog, createRuntimePackPublication, metaPathForGuid } from '@forgeax/engine-pack/build';
|
|
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';
|
|
7
|
+
import { loadScriptablePack } from '@forgeax/engine-pack/source-node';
|
|
8
|
+
import { stat, readFile, mkdir, writeFile, rename, rm, readdir } from 'fs/promises';
|
|
9
|
+
import { createAcceptedPublication, ddcOutputDigest, DdcLifecycle, DdcGenerationSession } from '@forgeax/engine-ddc';
|
|
10
|
+
import { deriveVertexLayoutProjection, normalizeMeshPayload } from '@forgeax/engine-geometry';
|
|
11
|
+
import { BUILTIN_MESH_ASSETS } from '@forgeax/engine-pack/builtin';
|
|
9
12
|
import { NativeCookerRegistry } from '@forgeax/engine-pack/native-cooker';
|
|
10
|
-
import {
|
|
11
|
-
import { inventoryScriptablePackSource } from '@forgeax/engine-pack/source-node';
|
|
13
|
+
import { isEngineMaterial } from '@forgeax/engine-shader';
|
|
12
14
|
import { externalizeSceneAsset } from '@forgeax/engine-scene';
|
|
13
15
|
import { sha256 } from '@noble/hashes/sha2.js';
|
|
14
16
|
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
15
|
-
import { deriveVertexLayoutProjection } from '@forgeax/engine-geometry';
|
|
16
17
|
import { MESH_BIN_HEADER_V4_BYTES, writeMeshBinHeader } from '@forgeax/engine-pack/mesh-bin-contract';
|
|
17
|
-
import {
|
|
18
|
+
import { createHash, randomUUID } from 'crypto';
|
|
19
|
+
import { validatePack, isScriptablePackAssetKind as isScriptablePackAssetKind$1 } from '@forgeax/engine-pack';
|
|
20
|
+
import { canonicalDdcJson } from '@forgeax/engine-ddc/key';
|
|
18
21
|
|
|
19
22
|
// src/index.ts
|
|
20
23
|
function invalidProduct(field) {
|
|
@@ -42,8 +45,8 @@ async function sha256Hex(bytes2) {
|
|
|
42
45
|
if (subtle === void 0) throw new Error("Web Crypto API is required for importer digests");
|
|
43
46
|
const owned = new Uint8Array(bytes2.byteLength);
|
|
44
47
|
owned.set(bytes2);
|
|
45
|
-
const
|
|
46
|
-
return Array.from(new Uint8Array(
|
|
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("");
|
|
47
50
|
}
|
|
48
51
|
async function artifactDigest(bytes2) {
|
|
49
52
|
return `sha256:${await sha256Hex(bytes2)}`;
|
|
@@ -106,25 +109,192 @@ function finalizeImportProducts(product, inputFingerprint) {
|
|
|
106
109
|
const products = [];
|
|
107
110
|
for (const asset of product.assets) {
|
|
108
111
|
const artifacts = await artifactDescriptors(asset.artifacts);
|
|
109
|
-
const
|
|
112
|
+
const digest3 = await productDigest(asset, artifacts);
|
|
110
113
|
products.push({
|
|
111
114
|
guid: asset.guid,
|
|
112
115
|
payload: asset.payload,
|
|
113
116
|
refs: asset.refs.map((ref2) => ref2.guid),
|
|
114
117
|
artifacts,
|
|
115
|
-
digest,
|
|
118
|
+
digest: digest3,
|
|
116
119
|
receipt: {
|
|
117
120
|
guid: asset.guid,
|
|
118
121
|
origin: "sourceMeta",
|
|
119
122
|
status: "succeeded",
|
|
120
123
|
inputFingerprint,
|
|
121
|
-
outputDigest:
|
|
124
|
+
outputDigest: digest3
|
|
122
125
|
}
|
|
123
126
|
});
|
|
124
127
|
}
|
|
125
128
|
return products;
|
|
126
129
|
})();
|
|
127
130
|
}
|
|
131
|
+
function deriveDefaultLodScreenCoverages(levelCount) {
|
|
132
|
+
if (!Number.isInteger(levelCount) || levelCount < 1 || levelCount > 8) {
|
|
133
|
+
throw new RangeError("levelCount must be an integer in [1, 8]");
|
|
134
|
+
}
|
|
135
|
+
return Array.from(
|
|
136
|
+
{ length: levelCount - 1 },
|
|
137
|
+
(_, index) => Math.round(0.5 * 0.4 ** index * 1e6) / 1e6
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
function validateMeshLodContract(input) {
|
|
141
|
+
if (input.lods.length > 7) {
|
|
142
|
+
return err({
|
|
143
|
+
code: "mesh-lod-contract-invalid",
|
|
144
|
+
reason: "at most seven lower-detail levels are supported"
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (input.lodHysteresis !== void 0 && (!Number.isFinite(input.lodHysteresis) || input.lodHysteresis < 0 || input.lodHysteresis >= 1)) {
|
|
148
|
+
return err({
|
|
149
|
+
code: "mesh-lod-contract-invalid",
|
|
150
|
+
reason: "lodHysteresis must be finite and in [0, 1)"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (input.generation !== void 0 && (!Number.isSafeInteger(input.generation) || input.generation < 0)) {
|
|
154
|
+
return err({
|
|
155
|
+
code: "mesh-lod-contract-invalid",
|
|
156
|
+
reason: "generation must be a non-negative safe integer"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const guids = /* @__PURE__ */ new Set();
|
|
160
|
+
let previous = 1;
|
|
161
|
+
for (const level of input.lods) {
|
|
162
|
+
if (level.meshGuid.trim() === "" || guids.has(level.meshGuid)) {
|
|
163
|
+
return err({
|
|
164
|
+
code: "mesh-lod-contract-invalid",
|
|
165
|
+
reason: "LOD mesh GUIDs must be unique and non-empty"
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (!Number.isFinite(level.screenCoverage) || level.screenCoverage <= 0 || level.screenCoverage > 1) {
|
|
169
|
+
return err({
|
|
170
|
+
code: "mesh-lod-contract-invalid",
|
|
171
|
+
reason: "screenCoverage must be finite and in (0, 1]"
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (level.screenCoverage >= previous) {
|
|
175
|
+
return err({
|
|
176
|
+
code: "mesh-lod-contract-invalid",
|
|
177
|
+
reason: "screenCoverage must strictly decrease by level"
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
guids.add(level.meshGuid);
|
|
181
|
+
previous = level.screenCoverage;
|
|
182
|
+
}
|
|
183
|
+
if (input.refs !== void 0) {
|
|
184
|
+
const refs = new Set(input.refs);
|
|
185
|
+
for (const level of input.lods) {
|
|
186
|
+
if (!refs.has(level.meshGuid)) {
|
|
187
|
+
return err({
|
|
188
|
+
code: "mesh-lod-contract-invalid",
|
|
189
|
+
reason: "every lower-detail mesh GUID must be enclosed by root refs"
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (input.rootMeshGuid !== void 0 && input.refs !== void 0 && !input.refs.includes(input.rootMeshGuid)) {
|
|
195
|
+
return err({
|
|
196
|
+
code: "mesh-lod-contract-invalid",
|
|
197
|
+
reason: "root mesh GUID must be included in refs"
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
if (input.rootBounds !== void 0) {
|
|
201
|
+
if (!validBounds(input.rootBounds)) {
|
|
202
|
+
return err({
|
|
203
|
+
code: "mesh-lod-contract-invalid",
|
|
204
|
+
reason: "root bounds must be finite and ordered"
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
for (const bounds of input.lodBounds ?? []) {
|
|
208
|
+
if (!validBounds(bounds) || !encloses(input.rootBounds, bounds)) {
|
|
209
|
+
return err({
|
|
210
|
+
code: "mesh-lod-contract-invalid",
|
|
211
|
+
reason: "root bounds must enclose every lower-detail bounds"
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (input.lodBounds !== void 0 && input.lodBounds.length !== input.lods.length) {
|
|
217
|
+
return err({
|
|
218
|
+
code: "mesh-lod-contract-invalid",
|
|
219
|
+
reason: "lod bounds must cover every lower level"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
if (input.rootMaterialSlots !== void 0 || input.lodMaterialSlots !== void 0) {
|
|
223
|
+
const rootSlots = input.rootMaterialSlots ?? [];
|
|
224
|
+
const lowerSlots = input.lodMaterialSlots ?? [];
|
|
225
|
+
if (lowerSlots.length !== input.lods.length || lowerSlots.some((slots) => !sameSlots(rootSlots, slots))) {
|
|
226
|
+
return err({
|
|
227
|
+
code: "mesh-lod-contract-invalid",
|
|
228
|
+
reason: "lower-detail material slots must preserve root sourceKey order"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (input.relations !== void 0 && hasCycle(input.relations)) {
|
|
233
|
+
return err({ code: "mesh-lod-contract-invalid", reason: "LOD relations must be acyclic" });
|
|
234
|
+
}
|
|
235
|
+
return ok({ lods: input.lods });
|
|
236
|
+
}
|
|
237
|
+
function validBounds(bounds) {
|
|
238
|
+
const [minX, minY, minZ] = bounds.min;
|
|
239
|
+
const [maxX, maxY, maxZ] = bounds.max;
|
|
240
|
+
return [minX, minY, minZ, maxX, maxY, maxZ].every(Number.isFinite) && minX <= maxX && minY <= maxY && minZ <= maxZ;
|
|
241
|
+
}
|
|
242
|
+
function encloses(root, child) {
|
|
243
|
+
return child.min[0] >= root.min[0] && child.min[1] >= root.min[1] && child.min[2] >= root.min[2] && child.max[0] <= root.max[0] && child.max[1] <= root.max[1] && child.max[2] <= root.max[2];
|
|
244
|
+
}
|
|
245
|
+
function sameSlots(root, child) {
|
|
246
|
+
return root.length === child.length && root.every((slot, index) => slot.sourceKey === child[index]?.sourceKey);
|
|
247
|
+
}
|
|
248
|
+
function hasCycle(relations) {
|
|
249
|
+
const edges = /* @__PURE__ */ new Map();
|
|
250
|
+
for (const relation of relations)
|
|
251
|
+
edges.set(relation.from, [...edges.get(relation.from) ?? [], relation.to]);
|
|
252
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
253
|
+
const visited = /* @__PURE__ */ new Set();
|
|
254
|
+
const visit = (node) => {
|
|
255
|
+
if (visiting.has(node)) return true;
|
|
256
|
+
if (visited.has(node)) return false;
|
|
257
|
+
visiting.add(node);
|
|
258
|
+
for (const next of edges.get(node) ?? []) if (visit(next)) return true;
|
|
259
|
+
visiting.delete(node);
|
|
260
|
+
visited.add(node);
|
|
261
|
+
return false;
|
|
262
|
+
};
|
|
263
|
+
return [...edges.keys()].some(visit);
|
|
264
|
+
}
|
|
265
|
+
function reconcileMeshLodMeta(previous, next) {
|
|
266
|
+
const overlap = Math.min(previous.length, next.length);
|
|
267
|
+
for (let index = 0; index < overlap; index++) {
|
|
268
|
+
const oldEntry = previous[index];
|
|
269
|
+
const nextEntry = next[index];
|
|
270
|
+
if (oldEntry?.sourceKey !== nextEntry?.sourceKey) {
|
|
271
|
+
return err({
|
|
272
|
+
code: "mesh-lod-topology-change",
|
|
273
|
+
reason: "existing LOD source keys must remain prefix-stable",
|
|
274
|
+
previousIndices: [index],
|
|
275
|
+
nextIndices: [index]
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
if (oldEntry?.meshGuid !== nextEntry?.meshGuid) {
|
|
279
|
+
return err({
|
|
280
|
+
code: "mesh-lod-authority-conflict",
|
|
281
|
+
reason: `sourceKey ${nextEntry?.sourceKey ?? "<missing>"} changed mesh GUID`
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const defaults = deriveDefaultLodScreenCoverages(next.length + 1);
|
|
286
|
+
const lods = next.map((entry, index) => ({
|
|
287
|
+
...entry,
|
|
288
|
+
screenCoverage: previous[index]?.screenCoverage ?? entry.screenCoverage ?? defaults[index] ?? 0
|
|
289
|
+
}));
|
|
290
|
+
const valid = validateMeshLodContract({
|
|
291
|
+
lods: lods.map(({ meshGuid, screenCoverage }) => ({ meshGuid, screenCoverage }))
|
|
292
|
+
});
|
|
293
|
+
if (!valid.ok) return valid;
|
|
294
|
+
return ok({ lods });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/import-runner.ts
|
|
128
298
|
var SHADER_RESERVED_IMPORTER_KEY = "shader";
|
|
129
299
|
function isModuleLoadFailure(e) {
|
|
130
300
|
if (!(e instanceof Error)) return false;
|
|
@@ -135,6 +305,9 @@ function isModuleLoadFailure(e) {
|
|
|
135
305
|
const msg = e.message;
|
|
136
306
|
return msg.includes("Cannot find module") || msg.includes("native addon") || msg.includes(".node");
|
|
137
307
|
}
|
|
308
|
+
function declarationsSourceKey(declarations, guid) {
|
|
309
|
+
return declarations.find((declaration) => declaration.guid === guid)?.sourceKey;
|
|
310
|
+
}
|
|
138
311
|
function normaliseForPack(value) {
|
|
139
312
|
if (value === null || value === void 0) return value;
|
|
140
313
|
if (value instanceof Float32Array || value instanceof Float64Array || value instanceof Uint8Array || value instanceof Uint16Array || value instanceof Uint32Array || value instanceof Int8Array || value instanceof Int16Array || value instanceof Int32Array) {
|
|
@@ -444,6 +617,37 @@ async function runImport(meta, registry, fs) {
|
|
|
444
617
|
);
|
|
445
618
|
}
|
|
446
619
|
const produced = product.assets;
|
|
620
|
+
for (const asset of produced) {
|
|
621
|
+
if (asset.kind !== "mesh" || asset.payload === null || typeof asset.payload !== "object")
|
|
622
|
+
continue;
|
|
623
|
+
const payload = asset.payload;
|
|
624
|
+
if (payload.lods === void 0) continue;
|
|
625
|
+
const lods = payload.lods.map((level) => ({
|
|
626
|
+
meshGuid: typeof level.meshGuid === "string" ? level.meshGuid : typeof level.mesh === "string" ? level.mesh : JSON.stringify(level.mesh),
|
|
627
|
+
screenCoverage: level.screenCoverage
|
|
628
|
+
}));
|
|
629
|
+
const validated = validateMeshLodContract({
|
|
630
|
+
lods,
|
|
631
|
+
...payload.lodHysteresis === void 0 ? {} : { lodHysteresis: payload.lodHysteresis }
|
|
632
|
+
});
|
|
633
|
+
if (!validated.ok) {
|
|
634
|
+
return errResult(
|
|
635
|
+
new ImportError({
|
|
636
|
+
code: validated.error.code,
|
|
637
|
+
expected: "MeshAsset LOD facts to satisfy the shared contract",
|
|
638
|
+
hint: IMPORT_ERROR_HINTS[validated.error.code],
|
|
639
|
+
detail: {
|
|
640
|
+
meshLodSourceKey: declarationsSourceKey(meta.subAssets, asset.guid),
|
|
641
|
+
reason: validated.error.reason,
|
|
642
|
+
...validated.error.code === "mesh-lod-topology-change" ? {
|
|
643
|
+
previousIndices: validated.error.previousIndices,
|
|
644
|
+
nextIndices: validated.error.nextIndices
|
|
645
|
+
} : {}
|
|
646
|
+
}
|
|
647
|
+
})
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
447
651
|
const declared = new Set(meta.subAssets.map((s) => s.guid));
|
|
448
652
|
const producedGuids = new Set(produced.map((a) => a.guid));
|
|
449
653
|
const unexpectedGuids = [...producedGuids].filter((g) => !declared.has(g));
|
|
@@ -575,104 +779,644 @@ function projectImportProductForBuild(product) {
|
|
|
575
779
|
}))
|
|
576
780
|
};
|
|
577
781
|
}
|
|
578
|
-
function
|
|
579
|
-
return
|
|
580
|
-
code: "mesh-bin-payload-invalid",
|
|
581
|
-
subject: "mesh-bin",
|
|
582
|
-
sourceKey,
|
|
583
|
-
expected,
|
|
584
|
-
actual,
|
|
585
|
-
recovery: "re-cook the source with its Meta sidecar through the build-time importer"
|
|
586
|
-
};
|
|
782
|
+
function record(value) {
|
|
783
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
587
784
|
}
|
|
588
|
-
function
|
|
589
|
-
return value
|
|
785
|
+
function isAsset(value) {
|
|
786
|
+
return record(value) && typeof value.kind === "string" && isScriptablePackAssetKind(value.kind);
|
|
590
787
|
}
|
|
591
|
-
function
|
|
592
|
-
|
|
593
|
-
|
|
788
|
+
function clone(value) {
|
|
789
|
+
return structuredClone(value);
|
|
790
|
+
}
|
|
791
|
+
function stable(value) {
|
|
792
|
+
if (value instanceof Uint8Array) return JSON.stringify(Array.from(value));
|
|
793
|
+
if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`;
|
|
594
794
|
if (value !== null && typeof value === "object") {
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
);
|
|
795
|
+
const object = value;
|
|
796
|
+
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stable(object[key])}`).join(",")}}`;
|
|
598
797
|
}
|
|
599
|
-
return value;
|
|
798
|
+
return JSON.stringify(value) ?? "null";
|
|
600
799
|
}
|
|
601
|
-
function
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
800
|
+
async function digest(value) {
|
|
801
|
+
const crypto = globalThis.crypto?.subtle;
|
|
802
|
+
if (crypto === void 0) throw new Error("Web Crypto API is required for Pack fingerprints");
|
|
803
|
+
const bytes2 = await crypto.digest("SHA-256", new TextEncoder().encode(stable(value)));
|
|
804
|
+
return `sha256:${Array.from(new Uint8Array(bytes2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
805
|
+
}
|
|
806
|
+
function observedReader(source) {
|
|
807
|
+
const reads = /* @__PURE__ */ new Map();
|
|
808
|
+
const reader = {
|
|
809
|
+
async readByGuid(guid) {
|
|
810
|
+
const key = AssetGuid.format(guid).toLowerCase();
|
|
811
|
+
const cached = reads.get(key);
|
|
812
|
+
if (cached !== void 0) return ok(clone(cached.asset));
|
|
813
|
+
if (source === void 0) {
|
|
814
|
+
return err(
|
|
815
|
+
new AssetError({
|
|
816
|
+
code: "asset-not-found",
|
|
817
|
+
expected: `a published Asset snapshot for content dependency ${key}`,
|
|
818
|
+
hint: "publish the dependency or remove the content read from the Pack build",
|
|
819
|
+
detail: { sourcePath: key }
|
|
820
|
+
})
|
|
821
|
+
);
|
|
614
822
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
823
|
+
const result = await source.readByGuid(guid);
|
|
824
|
+
if (!result.ok) return result;
|
|
825
|
+
const asset = clone(result.value.asset);
|
|
826
|
+
reads.set(key, {
|
|
827
|
+
guid: key,
|
|
828
|
+
asset,
|
|
829
|
+
generation: result.value.generation,
|
|
830
|
+
digest: result.value.digest
|
|
831
|
+
});
|
|
832
|
+
return ok(clone(asset));
|
|
620
833
|
}
|
|
621
|
-
|
|
834
|
+
};
|
|
835
|
+
return { reader, reads };
|
|
836
|
+
}
|
|
837
|
+
function buildContext(packageId, values, reader) {
|
|
838
|
+
if (values === void 0) return { packageId, readByGuid: reader.readByGuid };
|
|
839
|
+
return { packageId, values, readByGuid: reader.readByGuid };
|
|
840
|
+
}
|
|
841
|
+
function sourceKeyFailure(sourcePath, sourceKey) {
|
|
622
842
|
return {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
...payload.morphWeights === void 0 ? {} : { morphWeights: jsonValue(payload.morphWeights) }
|
|
843
|
+
code: "pack-source-key-invalid",
|
|
844
|
+
expected: "a sourceKey matching the Pack source-key grammar",
|
|
845
|
+
hint: "return stable lower-case semantic keys instead of paths or output indexes",
|
|
846
|
+
detail: { sourcePath, sourceKey }
|
|
628
847
|
};
|
|
629
848
|
}
|
|
630
|
-
function
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
849
|
+
function outputValueError(sourcePath, sourceKey, expected, actual) {
|
|
850
|
+
return {
|
|
851
|
+
code: "pack-parameter-invalid",
|
|
852
|
+
expected,
|
|
853
|
+
hint: "repair the build output and rebuild the Pack from a fresh generation",
|
|
854
|
+
detail: { sourcePath, sourceKey, actual: typeof actual === "string" ? actual : typeof actual }
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
function referenceError(code, sourcePath, guids) {
|
|
858
|
+
return {
|
|
859
|
+
code,
|
|
860
|
+
expected: code === "pack-output-reference-missing" ? "every output reference to resolve to a local or published AssetGuid" : "removed output GUIDs to have no incoming references",
|
|
861
|
+
hint: code === "pack-output-reference-missing" ? "build or publish the referenced Pack before verifying this output" : "migrate incoming references before publishing the topology change",
|
|
862
|
+
detail: { sourcePath, guids: [...guids].sort() }
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
function productError(sourcePath, sourceKey, producer, product) {
|
|
866
|
+
if (!record(product)) {
|
|
867
|
+
return outputValueError(
|
|
868
|
+
sourcePath,
|
|
869
|
+
sourceKey,
|
|
870
|
+
`producer ${producer.kind} to return an asset product object`,
|
|
871
|
+
product
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
if (!Array.isArray(product.refs)) {
|
|
875
|
+
return outputValueError(
|
|
876
|
+
sourcePath,
|
|
877
|
+
sourceKey,
|
|
878
|
+
`producer ${producer.kind} to return a refs array`,
|
|
879
|
+
product.refs
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
if (!record(product.artifacts)) {
|
|
883
|
+
return outputValueError(
|
|
884
|
+
sourcePath,
|
|
885
|
+
sourceKey,
|
|
886
|
+
`producer ${producer.kind} to return an artifacts object`,
|
|
887
|
+
product.artifacts
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
const payload = product.payload;
|
|
891
|
+
if (!record(payload) || payload.kind !== producer.kind) {
|
|
892
|
+
return outputValueError(
|
|
893
|
+
sourcePath,
|
|
894
|
+
sourceKey,
|
|
895
|
+
`producer ${producer.kind} to return a matching payload kind`,
|
|
896
|
+
payload
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
for (const ref2 of product.refs) {
|
|
900
|
+
if (!record(ref2) || typeof ref2.guid !== "string" || !AssetGuid.parse(ref2.guid).ok) {
|
|
901
|
+
return outputValueError(
|
|
902
|
+
sourcePath,
|
|
903
|
+
sourceKey,
|
|
904
|
+
"producer refs to contain valid AssetGuid values",
|
|
905
|
+
ref2
|
|
637
906
|
);
|
|
638
907
|
}
|
|
639
|
-
|
|
908
|
+
}
|
|
909
|
+
for (const [key, artifact] of Object.entries(product.artifacts)) {
|
|
910
|
+
if (key.length === 0 || key.startsWith("/") || key.includes("..") || key.includes("\\") || !record(artifact) || typeof artifact.mediaType !== "string" || !(artifact.bytes instanceof Uint8Array)) {
|
|
911
|
+
return outputValueError(
|
|
912
|
+
sourcePath,
|
|
913
|
+
sourceKey,
|
|
914
|
+
"asset-local artifacts with safe keys and bytes",
|
|
915
|
+
key
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return void 0;
|
|
920
|
+
}
|
|
921
|
+
function errorCode(value) {
|
|
922
|
+
return record(value) && typeof value.code === "string" ? value.code : void 0;
|
|
923
|
+
}
|
|
924
|
+
function normalizedGuidSet(value) {
|
|
925
|
+
return value === void 0 ? void 0 : new Set([...value].map((guid) => guid.toLowerCase()));
|
|
926
|
+
}
|
|
927
|
+
async function buildScriptablePack(options) {
|
|
928
|
+
const subjectPackageId = options.subjectPackageId ?? options.definition.packageId;
|
|
929
|
+
const availableGuids = normalizedGuidSet(options.availableGuids);
|
|
930
|
+
const observed = observedReader(options.assetSource);
|
|
931
|
+
let effectiveValues;
|
|
932
|
+
if ("parameters" in options.definition) {
|
|
933
|
+
const resolved = resolvePackParameterValues(
|
|
934
|
+
options.definition,
|
|
935
|
+
options.values ?? {},
|
|
936
|
+
options.inheritedValues
|
|
937
|
+
);
|
|
938
|
+
if (!resolved.ok) return resolved;
|
|
939
|
+
effectiveValues = resolved.value;
|
|
940
|
+
} else if (options.values !== void 0 && Object.keys(options.values).length > 0) {
|
|
941
|
+
return err(
|
|
942
|
+
outputValueError(
|
|
943
|
+
options.sourcePath,
|
|
944
|
+
"$.values",
|
|
945
|
+
"zero-parameter Packs to omit values and instance capabilities",
|
|
946
|
+
options.values
|
|
947
|
+
)
|
|
948
|
+
);
|
|
949
|
+
} else if (options.subjectPackageId !== void 0 && PackageId.format(options.subjectPackageId).toLowerCase() !== PackageId.format(options.definition.packageId).toLowerCase()) {
|
|
950
|
+
return err({
|
|
951
|
+
code: "pack-parent-has-no-parameters",
|
|
952
|
+
expected: "a ScriptablePack source with parameters for an independent instance packageId",
|
|
953
|
+
hint: "use clone for a zero-parameter Pack instead of building it as an instance",
|
|
954
|
+
detail: {
|
|
955
|
+
sourcePath: options.sourcePath,
|
|
956
|
+
rootPackageId: PackageId.format(options.definition.packageId),
|
|
957
|
+
subjectPackageId: PackageId.format(options.subjectPackageId)
|
|
958
|
+
}
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
let built;
|
|
962
|
+
try {
|
|
963
|
+
const context = buildContext(subjectPackageId, effectiveValues, observed.reader);
|
|
964
|
+
built = options.definition.build(context);
|
|
965
|
+
built = await built;
|
|
966
|
+
} catch (cause) {
|
|
967
|
+
return err(
|
|
968
|
+
new ImportError({
|
|
969
|
+
code: "import-internal-error",
|
|
970
|
+
expected: "Pack build to return a structured Result without throwing",
|
|
971
|
+
hint: "repair the authoring function and return err(...) for expected failures",
|
|
972
|
+
detail: {
|
|
973
|
+
reason: `${options.sourcePath}: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
974
|
+
}
|
|
975
|
+
})
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
if (!record(built) || typeof built.ok !== "boolean") {
|
|
979
|
+
return err(
|
|
980
|
+
new ImportError({
|
|
981
|
+
code: "import-internal-error",
|
|
982
|
+
expected: "Pack build to return a Result object",
|
|
983
|
+
hint: "return ok(sourceKeyToAsset) or err(structuredError) from the authoring function",
|
|
984
|
+
detail: { reason: `${options.sourcePath}: malformed build result` }
|
|
985
|
+
})
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
if (!built.ok) {
|
|
989
|
+
if (errorCode(built.error) !== void 0) return err(built.error);
|
|
990
|
+
return err(
|
|
991
|
+
new ImportError({
|
|
992
|
+
code: "import-internal-error",
|
|
993
|
+
expected: "a structured Pack build error",
|
|
994
|
+
hint: "return an error carrying code, expected, hint and detail",
|
|
995
|
+
detail: { reason: `${options.sourcePath}: ${String(built.error)}` }
|
|
996
|
+
})
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
if (!record(built.value)) {
|
|
1000
|
+
return err(
|
|
1001
|
+
outputValueError(
|
|
1002
|
+
options.sourcePath,
|
|
1003
|
+
"$",
|
|
1004
|
+
"build to return a sourceKey-to-Asset object",
|
|
1005
|
+
built.value
|
|
1006
|
+
)
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
const imported = [];
|
|
1010
|
+
const stagedOutputs = [];
|
|
1011
|
+
const localGuids = /* @__PURE__ */ new Set();
|
|
1012
|
+
for (const sourceKey of Object.keys(built.value).sort()) {
|
|
1013
|
+
if (!isValidPackSourceKey(sourceKey))
|
|
1014
|
+
return err(sourceKeyFailure(options.sourcePath, sourceKey));
|
|
1015
|
+
const asset = built.value[sourceKey];
|
|
1016
|
+
if (!isAsset(asset)) {
|
|
640
1017
|
return err(
|
|
641
|
-
|
|
1018
|
+
outputValueError(
|
|
1019
|
+
options.sourcePath,
|
|
1020
|
+
sourceKey,
|
|
1021
|
+
"a concrete Asset with a supported kind",
|
|
1022
|
+
asset
|
|
1023
|
+
)
|
|
642
1024
|
);
|
|
643
1025
|
}
|
|
644
|
-
const
|
|
645
|
-
const
|
|
646
|
-
if (
|
|
1026
|
+
const guid = AssetGuid.format(AssetGuid.derive(subjectPackageId, sourceKey));
|
|
1027
|
+
const normalizedGuid = guid.toLowerCase();
|
|
1028
|
+
if (localGuids.has(normalizedGuid) || availableGuids?.has(normalizedGuid)) {
|
|
1029
|
+
return err({
|
|
1030
|
+
code: "pack-guid-collision",
|
|
1031
|
+
expected: "derived output GUIDs to be unique in the global source index",
|
|
1032
|
+
hint: "change the colliding packageId or repair the source index before publishing",
|
|
1033
|
+
detail: { sourcePath: options.sourcePath, guid }
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
localGuids.add(normalizedGuid);
|
|
1037
|
+
const producer = options.outputs.get(asset.kind);
|
|
1038
|
+
if (producer === void 0) {
|
|
647
1039
|
return err(
|
|
648
|
-
|
|
1040
|
+
outputValueError(
|
|
1041
|
+
options.sourcePath,
|
|
649
1042
|
sourceKey,
|
|
650
|
-
|
|
651
|
-
|
|
1043
|
+
`a registered output producer for ${asset.kind}`,
|
|
1044
|
+
asset.kind
|
|
652
1045
|
)
|
|
653
1046
|
);
|
|
654
1047
|
}
|
|
655
|
-
|
|
656
|
-
|
|
1048
|
+
let produced;
|
|
1049
|
+
try {
|
|
1050
|
+
produced = await producer.produce({ guid, sourceKey, asset });
|
|
1051
|
+
} catch (cause) {
|
|
657
1052
|
return err(
|
|
658
|
-
|
|
1053
|
+
new ImportError({
|
|
1054
|
+
code: "import-internal-error",
|
|
1055
|
+
expected: `producer ${producer.kind} to return a structured Result without throwing`,
|
|
1056
|
+
hint: "repair the output producer and return err(...) for expected failures",
|
|
1057
|
+
detail: {
|
|
1058
|
+
reason: `${options.sourcePath}:${sourceKey}: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
1059
|
+
}
|
|
1060
|
+
})
|
|
659
1061
|
);
|
|
660
1062
|
}
|
|
661
|
-
if (
|
|
1063
|
+
if (!record(produced) || typeof produced.ok !== "boolean") {
|
|
662
1064
|
return err(
|
|
663
|
-
|
|
1065
|
+
outputValueError(
|
|
1066
|
+
options.sourcePath,
|
|
664
1067
|
sourceKey,
|
|
665
|
-
`
|
|
666
|
-
|
|
1068
|
+
`producer ${producer.kind} to return a Result`,
|
|
1069
|
+
produced
|
|
667
1070
|
)
|
|
668
1071
|
);
|
|
669
1072
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1073
|
+
if (!produced.ok) {
|
|
1074
|
+
if (errorCode(produced.error) !== void 0) return err(produced.error);
|
|
1075
|
+
return err(
|
|
1076
|
+
new ImportError({
|
|
1077
|
+
code: "import-internal-error",
|
|
1078
|
+
expected: `producer ${producer.kind} to return a structured error`,
|
|
1079
|
+
hint: "return an error carrying code, expected, hint and detail",
|
|
1080
|
+
detail: { reason: `${options.sourcePath}:${sourceKey}: ${String(produced.error)}` }
|
|
1081
|
+
})
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
const invalidProduct2 = productError(options.sourcePath, sourceKey, producer, produced.value);
|
|
1085
|
+
if (invalidProduct2 !== void 0) return err(invalidProduct2);
|
|
1086
|
+
const product2 = produced.value;
|
|
1087
|
+
imported.push({
|
|
1088
|
+
guid,
|
|
1089
|
+
kind: asset.kind,
|
|
1090
|
+
payload: product2.payload,
|
|
1091
|
+
refs: product2.refs,
|
|
1092
|
+
artifacts: product2.artifacts
|
|
1093
|
+
});
|
|
1094
|
+
stagedOutputs.push({
|
|
1095
|
+
guid: AssetGuid.derive(subjectPackageId, sourceKey),
|
|
1096
|
+
sourceKey,
|
|
1097
|
+
asset: clone(asset),
|
|
1098
|
+
digest: await digest(asset)
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
1102
|
+
for (const asset of imported) {
|
|
1103
|
+
for (const ref2 of asset.refs) {
|
|
1104
|
+
const guid = ref2.guid.toLowerCase();
|
|
1105
|
+
if (!localGuids.has(guid)) referenced.add(guid);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
if (options.deferReferenceValidation !== true) {
|
|
1109
|
+
const missing = [...referenced].filter(
|
|
1110
|
+
(guid) => availableGuids !== void 0 && !availableGuids.has(guid)
|
|
1111
|
+
);
|
|
1112
|
+
if (missing.length > 0)
|
|
1113
|
+
return err(referenceError("pack-output-reference-missing", options.sourcePath, missing));
|
|
1114
|
+
}
|
|
1115
|
+
const externalEvidence = [...observed.reads.values()].sort((left, right) => left.guid.localeCompare(right.guid)).map(
|
|
1116
|
+
(read) => ({
|
|
1117
|
+
guid: read.guid,
|
|
1118
|
+
usage: referenced.has(read.guid) ? "both" : "content",
|
|
1119
|
+
generation: read.generation,
|
|
1120
|
+
digest: read.digest
|
|
1121
|
+
})
|
|
1122
|
+
);
|
|
1123
|
+
const inputFingerprint = await digest({
|
|
1124
|
+
packageId: PackageId.format(subjectPackageId),
|
|
1125
|
+
sourcePath: options.sourcePath,
|
|
1126
|
+
sourceClosure: options.sourceClosure ?? [],
|
|
1127
|
+
values: effectiveValues,
|
|
1128
|
+
externalEvidence: externalEvidence.map(({ guid, usage, digest: evidenceDigest }) => ({
|
|
1129
|
+
guid,
|
|
1130
|
+
usage,
|
|
1131
|
+
digest: evidenceDigest
|
|
1132
|
+
})),
|
|
1133
|
+
authoringContractVersion: options.authoringContractVersion ?? "scriptable-pack/1",
|
|
1134
|
+
producerVersions: options.outputs.versions()
|
|
1135
|
+
});
|
|
1136
|
+
const refs = imported.flatMap((asset) => asset.refs);
|
|
1137
|
+
const artifacts = Object.fromEntries(
|
|
1138
|
+
imported.flatMap(
|
|
1139
|
+
(asset) => Object.entries(asset.artifacts).map(([key, artifact]) => [`${asset.guid}/${key}`, artifact])
|
|
1140
|
+
)
|
|
1141
|
+
);
|
|
1142
|
+
const product = createImportProduct({
|
|
1143
|
+
assets: imported,
|
|
1144
|
+
sourceDependencies: (options.sourceClosure ?? []).map((entry) => entry.path),
|
|
1145
|
+
refs,
|
|
1146
|
+
artifacts,
|
|
1147
|
+
receipts: imported.map((asset) => ({
|
|
1148
|
+
guid: asset.guid,
|
|
1149
|
+
origin: "authoredPack",
|
|
1150
|
+
status: "succeeded",
|
|
1151
|
+
inputFingerprint
|
|
1152
|
+
})),
|
|
1153
|
+
diagnostics: [],
|
|
1154
|
+
sourceRevision: inputFingerprint,
|
|
1155
|
+
sourceKey: options.sourcePath
|
|
1156
|
+
});
|
|
1157
|
+
if (!product.ok) return err(product.error);
|
|
1158
|
+
return ok({
|
|
1159
|
+
product: product.value,
|
|
1160
|
+
stagedOutputs,
|
|
1161
|
+
externalEvidence,
|
|
1162
|
+
inputFingerprint,
|
|
1163
|
+
...options.publication === void 0 ? {} : { publication: options.publication }
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
function stagedSource(staged, fallback) {
|
|
1167
|
+
return {
|
|
1168
|
+
async readByGuid(guid) {
|
|
1169
|
+
const key = AssetGuid.format(guid).toLowerCase();
|
|
1170
|
+
const local = staged.get(key);
|
|
1171
|
+
if (local !== void 0) {
|
|
1172
|
+
return ok({
|
|
1173
|
+
asset: clone(local.asset),
|
|
1174
|
+
generation: 1,
|
|
1175
|
+
digest: local.digest ?? "sha256:staged"
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
if (fallback === void 0) {
|
|
1179
|
+
return err({
|
|
1180
|
+
code: "asset-not-found",
|
|
1181
|
+
expected: "a staged or published content dependency",
|
|
1182
|
+
hint: "wait for the dependency subject to materialize",
|
|
1183
|
+
detail: { guid: key }
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
return fallback.readByGuid(guid);
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
async function buildScriptablePackWorklist(options) {
|
|
1191
|
+
const orderedSubjects = [...options.subjects].sort(
|
|
1192
|
+
(left, right) => left.sourcePath.localeCompare(right.sourcePath)
|
|
1193
|
+
);
|
|
1194
|
+
const pending = new Map(
|
|
1195
|
+
orderedSubjects.map((subject, index) => [`${index}:${subject.sourcePath}`, subject])
|
|
1196
|
+
);
|
|
1197
|
+
const staged = /* @__PURE__ */ new Map();
|
|
1198
|
+
const results = /* @__PURE__ */ new Map();
|
|
1199
|
+
const availableGuids = /* @__PURE__ */ new Set([
|
|
1200
|
+
...normalizedGuidSet(options.availableGuids) ?? [],
|
|
1201
|
+
...BUILTIN_MESH_ASSETS.map((asset) => asset.guid.toLowerCase())
|
|
1202
|
+
]);
|
|
1203
|
+
const maxPasses = options.maxPasses ?? Math.max(1, options.subjects.length + 1);
|
|
1204
|
+
let iterations = 0;
|
|
1205
|
+
for (; iterations < maxPasses && pending.size > 0; iterations += 1) {
|
|
1206
|
+
let progress = false;
|
|
1207
|
+
const waiting = /* @__PURE__ */ new Set();
|
|
1208
|
+
for (const [key, subject] of pending) {
|
|
1209
|
+
const result = await buildScriptablePack({
|
|
1210
|
+
definition: subject.definition,
|
|
1211
|
+
sourcePath: subject.sourcePath,
|
|
1212
|
+
...subject.subjectPackageId === void 0 ? {} : { subjectPackageId: subject.subjectPackageId },
|
|
1213
|
+
...subject.values === void 0 ? {} : { values: subject.values },
|
|
1214
|
+
...subject.inheritedValues === void 0 ? {} : { inheritedValues: subject.inheritedValues },
|
|
1215
|
+
...subject.sourceClosure === void 0 ? {} : { sourceClosure: subject.sourceClosure },
|
|
1216
|
+
outputs: options.outputs,
|
|
1217
|
+
assetSource: stagedSource(staged, options.assetSource),
|
|
1218
|
+
availableGuids: /* @__PURE__ */ new Set([...availableGuids, ...staged.keys()]),
|
|
1219
|
+
deferReferenceValidation: true
|
|
1220
|
+
});
|
|
1221
|
+
if (result.ok) {
|
|
1222
|
+
results.set(key, result.value);
|
|
1223
|
+
for (const output of result.value.stagedOutputs)
|
|
1224
|
+
staged.set(AssetGuid.format(output.guid).toLowerCase(), output);
|
|
1225
|
+
pending.delete(key);
|
|
1226
|
+
progress = true;
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
if (errorCode(result.error) === "asset-not-found") {
|
|
1230
|
+
const detail = record(result.error) && record(result.error.detail) ? result.error.detail : void 0;
|
|
1231
|
+
const guid = detail !== void 0 && typeof detail.guid === "string" ? detail.guid : void 0;
|
|
1232
|
+
if (guid !== void 0) waiting.add(guid.toLowerCase());
|
|
1233
|
+
continue;
|
|
1234
|
+
}
|
|
1235
|
+
return result;
|
|
1236
|
+
}
|
|
1237
|
+
if (pending.size === 0) break;
|
|
1238
|
+
if (!progress) {
|
|
1239
|
+
return err({
|
|
1240
|
+
code: "pack-content-dependency-stalled",
|
|
1241
|
+
expected: "the content dependency worklist to make progress",
|
|
1242
|
+
hint: "inspect waitingGuids and repair the missing output or content-read cycle, then rebuild",
|
|
1243
|
+
detail: {
|
|
1244
|
+
waitingGuids: [...waiting].sort(),
|
|
1245
|
+
pendingSubjects: [...pending.values()].map((subject) => subject.sourcePath).sort(),
|
|
1246
|
+
iterations: iterations + 1
|
|
1247
|
+
}
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
if (pending.size > 0) {
|
|
1252
|
+
return err({
|
|
1253
|
+
code: "pack-content-dependency-stalled",
|
|
1254
|
+
expected: "the content dependency worklist to finish within its bounded retry budget",
|
|
1255
|
+
hint: "inspect pendingSubjects and waitingGuids, then repair the dependency graph",
|
|
1256
|
+
detail: {
|
|
1257
|
+
pendingSubjects: [...pending.values()].map((subject) => subject.sourcePath).sort(),
|
|
1258
|
+
waitingGuids: [],
|
|
1259
|
+
iterations
|
|
1260
|
+
}
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
const knownGuids = /* @__PURE__ */ new Set([...availableGuids, ...staged.keys()]);
|
|
1264
|
+
const missingReferences = /* @__PURE__ */ new Set();
|
|
1265
|
+
for (const product of results.values()) {
|
|
1266
|
+
const contentReads = new Set(product.externalEvidence.map((read) => read.guid.toLowerCase()));
|
|
1267
|
+
for (const asset of product.product.assets) {
|
|
1268
|
+
for (const reference of asset.refs) {
|
|
1269
|
+
const guid = reference.guid.toLowerCase();
|
|
1270
|
+
if (!knownGuids.has(guid) && !contentReads.has(guid)) missingReferences.add(guid);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (missingReferences.size > 0) {
|
|
1275
|
+
return err(
|
|
1276
|
+
referenceError("pack-output-reference-missing", "worklist", [...missingReferences].sort())
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
const removed = [...options.incomingRefs?.keys() ?? []].filter(
|
|
1280
|
+
(guid) => !staged.has(guid.toLowerCase())
|
|
1281
|
+
);
|
|
1282
|
+
const referencedRemoved = removed.filter(
|
|
1283
|
+
(guid) => (options.incomingRefs?.get(guid) ?? []).length > 0
|
|
1284
|
+
);
|
|
1285
|
+
if (referencedRemoved.length > 0)
|
|
1286
|
+
return err(referenceError("pack-output-reference-conflict", "worklist", referencedRemoved));
|
|
1287
|
+
return ok({
|
|
1288
|
+
products: [...results.values()].map((result) => result.product),
|
|
1289
|
+
buildProducts: [...results.values()],
|
|
1290
|
+
stagedOutputs: [...staged.values()],
|
|
1291
|
+
iterations: pending.size === 0 && options.subjects.length > 0 ? iterations + 1 : iterations
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
function failure(sourceKey, expected, actual) {
|
|
1295
|
+
return {
|
|
1296
|
+
code: "mesh-bin-payload-invalid",
|
|
1297
|
+
subject: "mesh-bin",
|
|
1298
|
+
sourceKey,
|
|
1299
|
+
expected,
|
|
1300
|
+
actual,
|
|
1301
|
+
recovery: "re-cook the source with its Meta sidecar through the build-time importer"
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
function asAttributeMap(value) {
|
|
1305
|
+
return value ?? {};
|
|
1306
|
+
}
|
|
1307
|
+
function jsonValue(value) {
|
|
1308
|
+
if (value instanceof Float32Array || value instanceof Uint16Array) return Array.from(value);
|
|
1309
|
+
if (Array.isArray(value)) return value.map(jsonValue);
|
|
1310
|
+
if (value !== null && typeof value === "object") {
|
|
1311
|
+
return Object.fromEntries(
|
|
1312
|
+
Object.entries(value).map(([key, nested]) => [key, jsonValue(nested)])
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
return value;
|
|
1316
|
+
}
|
|
1317
|
+
function refsMeta(payload, refs) {
|
|
1318
|
+
const materialSlots = (payload.materialSlots ?? [{ slotName: "Default" }]).map(
|
|
1319
|
+
(slot, slotIndex) => {
|
|
1320
|
+
const defaultMaterial = slot.defaultMaterial;
|
|
1321
|
+
let defaultMaterialRef;
|
|
1322
|
+
if (defaultMaterial !== void 0) {
|
|
1323
|
+
const guid = AssetGuid$1.format(defaultMaterial);
|
|
1324
|
+
defaultMaterialRef = refs.findIndex((candidate) => candidate.toLowerCase() === guid);
|
|
1325
|
+
if (defaultMaterialRef < 0) {
|
|
1326
|
+
throw new Error(
|
|
1327
|
+
`material slot ${slotIndex} default material ${guid} is absent from refs`
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return {
|
|
1332
|
+
slotName: slot.slotName,
|
|
1333
|
+
...slot.sourceKey === void 0 ? {} : { sourceKey: slot.sourceKey },
|
|
1334
|
+
...defaultMaterialRef === void 0 ? {} : { defaultMaterialRef }
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
);
|
|
1338
|
+
if (payload.lods !== void 0 && payload.lods.length > 7) {
|
|
1339
|
+
throw new Error("MeshAsset LOD chain supports at most seven lower-detail levels");
|
|
1340
|
+
}
|
|
1341
|
+
let previousCoverage = 1;
|
|
1342
|
+
const seenLodGuids = /* @__PURE__ */ new Set();
|
|
1343
|
+
const lods = payload.lods?.map((lod, lodIndex) => {
|
|
1344
|
+
const guid = AssetGuid$1.format(lod.mesh).toLowerCase();
|
|
1345
|
+
const meshRef = refs.findIndex((candidate) => candidate.toLowerCase() === guid);
|
|
1346
|
+
if (meshRef < 0) {
|
|
1347
|
+
throw new Error(`LOD ${lodIndex} mesh ${guid} is absent from refs`);
|
|
1348
|
+
}
|
|
1349
|
+
if (seenLodGuids.has(guid)) {
|
|
1350
|
+
throw new Error(`LOD ${lodIndex} mesh ${guid} is duplicated`);
|
|
1351
|
+
}
|
|
1352
|
+
if (!Number.isFinite(lod.screenCoverage) || lod.screenCoverage <= 0 || lod.screenCoverage > 1 || lod.screenCoverage >= previousCoverage) {
|
|
1353
|
+
throw new Error(
|
|
1354
|
+
`LOD ${lodIndex} screenCoverage must be finite, in (0, 1], and strictly decreasing`
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
seenLodGuids.add(guid);
|
|
1358
|
+
previousCoverage = lod.screenCoverage;
|
|
1359
|
+
return { meshRef, screenCoverage: lod.screenCoverage };
|
|
1360
|
+
});
|
|
1361
|
+
if (payload.lodHysteresis !== void 0 && (!Number.isFinite(payload.lodHysteresis) || payload.lodHysteresis < 0 || payload.lodHysteresis >= 1)) {
|
|
1362
|
+
throw new Error("lodHysteresis must be finite and in [0, 1)");
|
|
1363
|
+
}
|
|
1364
|
+
return {
|
|
1365
|
+
submeshes: payload.submeshes === void 0 || payload.submeshes.length === 0 ? [{ indexOffset: 0, indexCount: payload.indices?.length ?? 0, materialSlot: 0 }] : payload.submeshes,
|
|
1366
|
+
materialSlots,
|
|
1367
|
+
...payload.aabb === void 0 ? {} : { aabb: jsonValue(payload.aabb) },
|
|
1368
|
+
...payload.morphTargets === void 0 ? {} : { morphTargets: jsonValue(payload.morphTargets) },
|
|
1369
|
+
...payload.morphWeights === void 0 ? {} : { morphWeights: jsonValue(payload.morphWeights) },
|
|
1370
|
+
...lods === void 0 ? {} : { lods },
|
|
1371
|
+
...payload.lodHysteresis === void 0 ? {} : { lodHysteresis: payload.lodHysteresis }
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
function packMeshBinV4(payload, sourceKey, refs = []) {
|
|
1375
|
+
try {
|
|
1376
|
+
const vertices = payload.vertices;
|
|
1377
|
+
const indices = payload.indices;
|
|
1378
|
+
if (!(vertices instanceof Float32Array)) {
|
|
1379
|
+
return err(
|
|
1380
|
+
failure(sourceKey, "Float32Array interleaved vertices", "vertices is not Float32Array")
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
if (indices !== void 0 && !(indices instanceof Uint16Array || indices instanceof Uint32Array)) {
|
|
1384
|
+
return err(
|
|
1385
|
+
failure(sourceKey, "Uint16Array or Uint32Array indices", "indices has an unsupported type")
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
const attributes = asAttributeMap(payload.attributes);
|
|
1389
|
+
const projection = deriveVertexLayoutProjection(attributes);
|
|
1390
|
+
if (projection.attributes.length === 0 || projection.arrayStride === 0) {
|
|
1391
|
+
return err(
|
|
1392
|
+
failure(
|
|
1393
|
+
sourceKey,
|
|
1394
|
+
"a non-empty canonical geometry projection",
|
|
1395
|
+
"projection has no attributes"
|
|
1396
|
+
)
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
const vertexCount = payload.vertexCount ?? vertices.byteLength / projection.arrayStride;
|
|
1400
|
+
if (!Number.isSafeInteger(vertexCount) || vertexCount < 0) {
|
|
1401
|
+
return err(
|
|
1402
|
+
failure(sourceKey, "a non-negative safe vertex cardinality", `vertexCount=${vertexCount}`)
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
if (vertices.byteLength !== vertexCount * projection.arrayStride) {
|
|
1406
|
+
return err(
|
|
1407
|
+
failure(
|
|
1408
|
+
sourceKey,
|
|
1409
|
+
`vertices.byteLength=${vertexCount * projection.arrayStride}`,
|
|
1410
|
+
`vertices.byteLength=${vertices.byteLength}; stride=${projection.arrayStride}`
|
|
1411
|
+
)
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
for (const attribute of projection.attributes) {
|
|
1415
|
+
const value = attributes[attribute.key];
|
|
1416
|
+
const components = attribute.byteLength / (attribute.format === "uint16x4" ? 2 : 4);
|
|
1417
|
+
if (value === void 0 || !(value instanceof Float32Array) && !(value instanceof Uint16Array) || value.length !== vertexCount * components) {
|
|
1418
|
+
return err(
|
|
1419
|
+
failure(
|
|
676
1420
|
sourceKey,
|
|
677
1421
|
`${attribute.key} cardinality=${vertexCount * components}`,
|
|
678
1422
|
`${attribute.key} cardinality=${value?.byteLength ?? "missing"}`
|
|
@@ -733,388 +1477,42 @@ function packMeshBinV4(payload, sourceKey, refs = []) {
|
|
|
733
1477
|
offset += interleaved.byteLength;
|
|
734
1478
|
if (indices !== void 0 && indexBytes > 0) {
|
|
735
1479
|
out.set(new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength), offset);
|
|
736
|
-
offset += indexBytes;
|
|
737
|
-
}
|
|
738
|
-
out.set(meta, offset);
|
|
739
|
-
return ok(out);
|
|
740
|
-
} catch (error) {
|
|
741
|
-
return err(
|
|
742
|
-
failure(
|
|
743
|
-
sourceKey,
|
|
744
|
-
"valid canonical mesh payload",
|
|
745
|
-
error instanceof Error ? error.message : String(error)
|
|
746
|
-
)
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
function commonPathPrefix(paths) {
|
|
751
|
-
const first = paths[0];
|
|
752
|
-
if (first === void 0) return "";
|
|
753
|
-
const firstNormalized = first.replaceAll("\\", "/");
|
|
754
|
-
const firstDirectory = firstNormalized.slice(0, firstNormalized.lastIndexOf("/"));
|
|
755
|
-
const parts = firstDirectory.split("/");
|
|
756
|
-
let length = parts.length;
|
|
757
|
-
for (const path of paths.slice(1)) {
|
|
758
|
-
const normalized = path.replaceAll("\\", "/");
|
|
759
|
-
const candidate = normalized.slice(0, normalized.lastIndexOf("/")).split("/");
|
|
760
|
-
length = Math.min(length, candidate.length);
|
|
761
|
-
for (let index = 0; index < length; index += 1) {
|
|
762
|
-
if (parts[index] !== candidate[index]) {
|
|
763
|
-
length = index;
|
|
764
|
-
break;
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
return parts.slice(0, length).join("/");
|
|
769
|
-
}
|
|
770
|
-
function stableSourceClosure(closure) {
|
|
771
|
-
const root = commonPathPrefix(closure.map((entry) => entry.path));
|
|
772
|
-
return closure.map((entry) => ({
|
|
773
|
-
path: entry.path.replaceAll("\\", "/").slice(root.length).replace(/^\/+/, ""),
|
|
774
|
-
digest: entry.digest
|
|
775
|
-
})).sort((left, right) => left.path.localeCompare(right.path));
|
|
776
|
-
}
|
|
777
|
-
var AssetOutputProducerRegistry = class {
|
|
778
|
-
producers = /* @__PURE__ */ new Map();
|
|
779
|
-
register(producer) {
|
|
780
|
-
if (producer.kind.trim().length === 0 || producer.version.trim().length === 0) {
|
|
781
|
-
throw new TypeError("ScriptablePack output producer kind and version must be non-empty");
|
|
782
|
-
}
|
|
783
|
-
if (typeof producer.produce !== "function") {
|
|
784
|
-
throw new TypeError(`ScriptablePack output producer ${producer.kind} must expose produce`);
|
|
785
|
-
}
|
|
786
|
-
this.producers.set(producer.kind, producer);
|
|
787
|
-
}
|
|
788
|
-
get(kind) {
|
|
789
|
-
return this.producers.get(kind);
|
|
790
|
-
}
|
|
791
|
-
versions() {
|
|
792
|
-
return Object.fromEntries(
|
|
793
|
-
[...this.producers.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([kind, producer]) => [kind, producer.version])
|
|
794
|
-
);
|
|
795
|
-
}
|
|
796
|
-
};
|
|
797
|
-
function privateClone(value) {
|
|
798
|
-
return structuredClone(value);
|
|
799
|
-
}
|
|
800
|
-
function record(value) {
|
|
801
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
802
|
-
}
|
|
803
|
-
function isAsset(value) {
|
|
804
|
-
return record(value) && typeof value.kind === "string" && isScriptablePackAssetKind(value.kind);
|
|
805
|
-
}
|
|
806
|
-
function isStructuredDomainError(value) {
|
|
807
|
-
return value !== null && typeof value === "object" && typeof value.code === "string" && typeof value.expected === "string" && typeof value.hint === "string";
|
|
808
|
-
}
|
|
809
|
-
function remapBuildFailureSource(value, sourcePath) {
|
|
810
|
-
if (value === null || typeof value !== "object") return void 0;
|
|
811
|
-
const error = value;
|
|
812
|
-
if (error.code !== "pack-source-load-failed") return void 0;
|
|
813
|
-
if (error.detail === null || typeof error.detail !== "object") return void 0;
|
|
814
|
-
const detail = error.detail;
|
|
815
|
-
if (detail.phase !== "build") return void 0;
|
|
816
|
-
return {
|
|
817
|
-
...value,
|
|
818
|
-
detail: { ...detail, sourcePath }
|
|
819
|
-
};
|
|
820
|
-
}
|
|
821
|
-
function observedAssetReader(source) {
|
|
822
|
-
const reads = /* @__PURE__ */ new Map();
|
|
823
|
-
const reader = {
|
|
824
|
-
async readByGuid(guid) {
|
|
825
|
-
const key = AssetGuid.format(guid);
|
|
826
|
-
const cached = reads.get(key);
|
|
827
|
-
if (cached !== void 0) return ok(privateClone(cached.asset));
|
|
828
|
-
if (source === void 0) {
|
|
829
|
-
return err(
|
|
830
|
-
new AssetError({
|
|
831
|
-
code: "asset-not-found",
|
|
832
|
-
expected: `a host Asset snapshot source for ScriptablePack content read ${key}`,
|
|
833
|
-
hint: "configure the standard ScriptablePack asset source or remove the content read"
|
|
834
|
-
})
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
const result = await source.readByGuid(guid);
|
|
838
|
-
if (!result.ok) return result;
|
|
839
|
-
const fixed = privateClone(result.value.asset);
|
|
840
|
-
reads.set(key, {
|
|
841
|
-
guid: key,
|
|
842
|
-
asset: fixed,
|
|
843
|
-
generation: result.value.generation,
|
|
844
|
-
digest: result.value.digest
|
|
845
|
-
});
|
|
846
|
-
return ok(privateClone(fixed));
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
|
-
return { reader, reads };
|
|
850
|
-
}
|
|
851
|
-
function stable(value) {
|
|
852
|
-
if (value instanceof Uint8Array) return JSON.stringify(Array.from(value));
|
|
853
|
-
if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`;
|
|
854
|
-
if (value !== null && typeof value === "object") {
|
|
855
|
-
const record2 = value;
|
|
856
|
-
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stable(record2[key])}`).join(",")}}`;
|
|
857
|
-
}
|
|
858
|
-
return JSON.stringify(value) ?? "null";
|
|
859
|
-
}
|
|
860
|
-
async function fingerprint(value) {
|
|
861
|
-
const subtle = globalThis.crypto?.subtle;
|
|
862
|
-
if (subtle === void 0)
|
|
863
|
-
throw new Error("Web Crypto API is required for ScriptablePack fingerprints");
|
|
864
|
-
const digest = await subtle.digest("SHA-256", new TextEncoder().encode(stable(value)));
|
|
865
|
-
const hex = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
866
|
-
""
|
|
867
|
-
);
|
|
868
|
-
return `sha256:${hex}`;
|
|
869
|
-
}
|
|
870
|
-
function outputError(definition, output) {
|
|
871
|
-
const declaredKeys = Object.keys(definition.assets);
|
|
872
|
-
const outputKeys = Object.keys(output);
|
|
873
|
-
const outputKeySet = new Set(outputKeys);
|
|
874
|
-
const declaredKeySet = new Set(declaredKeys);
|
|
875
|
-
const missingKeys = declaredKeys.filter((key) => !outputKeySet.has(key));
|
|
876
|
-
const unexpectedSourceKeys = outputKeys.filter((key) => !declaredKeySet.has(key));
|
|
877
|
-
const kindMismatches = declaredKeys.flatMap((sourceKey) => {
|
|
878
|
-
const descriptor = definition.assets[sourceKey];
|
|
879
|
-
const value = output[sourceKey];
|
|
880
|
-
if (descriptor === void 0 || value === void 0) return [];
|
|
881
|
-
const actualKind = value !== null && typeof value === "object" && "kind" in value ? String(value.kind) : typeof value;
|
|
882
|
-
return actualKind === descriptor.kind ? [] : [{ sourceKey, expected: descriptor.kind, actual: actualKind }];
|
|
883
|
-
});
|
|
884
|
-
if (missingKeys.length === 0 && unexpectedSourceKeys.length === 0 && kindMismatches.length === 0) {
|
|
885
|
-
return void 0;
|
|
886
|
-
}
|
|
887
|
-
return {
|
|
888
|
-
code: "pack-source-output-invalid",
|
|
889
|
-
expected: "build output keys and kinds to exactly match definition.assets",
|
|
890
|
-
hint: "inspect sourceKey and GUID topology, then rebuild or cold-cook the ScriptablePack",
|
|
891
|
-
detail: {
|
|
892
|
-
missingGuids: missingKeys.map(
|
|
893
|
-
(key) => AssetGuid.format(definition.assets[key]?.guid)
|
|
894
|
-
),
|
|
895
|
-
unexpectedSourceKeys,
|
|
896
|
-
kindMismatches
|
|
897
|
-
}
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
function externalClosureError(declared, referenced, read) {
|
|
901
|
-
const used = /* @__PURE__ */ new Set([...referenced, ...read]);
|
|
902
|
-
const undeclaredReferencedGuids = [...referenced].filter((guid) => !declared.has(guid));
|
|
903
|
-
const undeclaredReadGuids = [...read].filter((guid) => !declared.has(guid));
|
|
904
|
-
const unusedDeclaredGuids = [...declared].filter((guid) => !used.has(guid));
|
|
905
|
-
if (undeclaredReferencedGuids.length === 0 && undeclaredReadGuids.length === 0 && unusedDeclaredGuids.length === 0) {
|
|
906
|
-
return void 0;
|
|
907
|
-
}
|
|
908
|
-
return {
|
|
909
|
-
code: "pack-source-external-closure-mismatch",
|
|
910
|
-
expected: "externalAssets GUIDs to equal output external refs union AssetReader reads",
|
|
911
|
-
hint: "inspect refs and AssetReader reads, repair GUID declarations, then rebuild or cold-cook",
|
|
912
|
-
detail: {
|
|
913
|
-
undeclaredReferencedGuids: undeclaredReferencedGuids.sort(),
|
|
914
|
-
undeclaredReadGuids: undeclaredReadGuids.sort(),
|
|
915
|
-
unusedDeclaredGuids: unusedDeclaredGuids.sort()
|
|
916
|
-
}
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
function productContractError(sourceKey, kind, product) {
|
|
920
|
-
const mismatches = [];
|
|
921
|
-
if (product.payload.kind !== kind) {
|
|
922
|
-
mismatches.push({ sourceKey, expected: kind, actual: product.payload.kind });
|
|
923
|
-
}
|
|
924
|
-
for (const reference of product.refs) {
|
|
925
|
-
if (!AssetGuid.parse(reference.guid).ok) {
|
|
926
|
-
mismatches.push({
|
|
927
|
-
sourceKey,
|
|
928
|
-
expected: "every producer ref to contain a valid Asset GUID",
|
|
929
|
-
actual: reference.guid
|
|
930
|
-
});
|
|
931
|
-
break;
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
for (const [artifactKey, artifact] of Object.entries(product.artifacts)) {
|
|
935
|
-
if (artifactKey.length === 0 || artifactKey.startsWith("/") || artifactKey.includes("..") || artifactKey.includes("\\") || artifact.mediaType.trim().length === 0 || !(artifact.bytes instanceof Uint8Array)) {
|
|
936
|
-
mismatches.push({
|
|
937
|
-
sourceKey,
|
|
938
|
-
expected: "asset-local artifacts with safe keys, mediaType, and Uint8Array bytes",
|
|
939
|
-
actual: artifactKey
|
|
940
|
-
});
|
|
941
|
-
break;
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
if (mismatches.length === 0) return void 0;
|
|
945
|
-
return {
|
|
946
|
-
code: "pack-source-output-invalid",
|
|
947
|
-
expected: "producer output refs and asset-local artifacts to satisfy the Pack v2 contract",
|
|
948
|
-
hint: "inspect sourceKey and artifact provenance, repair refs or bytes, then rebuild or cold-cook",
|
|
949
|
-
detail: { missingGuids: [], unexpectedSourceKeys: [], kindMismatches: mismatches }
|
|
950
|
-
};
|
|
951
|
-
}
|
|
952
|
-
async function buildScriptablePack(options) {
|
|
953
|
-
const observed = observedAssetReader(options.assetSource);
|
|
954
|
-
let built;
|
|
955
|
-
try {
|
|
956
|
-
const build = options.definition.build;
|
|
957
|
-
built = await build(observed.reader);
|
|
958
|
-
} catch (error) {
|
|
959
|
-
return err(
|
|
960
|
-
new ImportError({
|
|
961
|
-
code: "import-internal-error",
|
|
962
|
-
expected: "ScriptablePack build to return a structured Result without throwing",
|
|
963
|
-
hint: "fix the build implementation and return a structured failure for expected authoring errors",
|
|
964
|
-
detail: { reason: error instanceof Error ? error.message : String(error) }
|
|
965
|
-
})
|
|
966
|
-
);
|
|
967
|
-
}
|
|
968
|
-
if (!built.ok) {
|
|
969
|
-
const remappedBuildFailure = remapBuildFailureSource(built.error, options.sourcePath);
|
|
970
|
-
if (remappedBuildFailure !== void 0) return err(remappedBuildFailure);
|
|
971
|
-
if (built.error instanceof ImportError || built.error instanceof AssetError || isStructuredDomainError(built.error)) {
|
|
972
|
-
return err(built.error);
|
|
1480
|
+
offset += indexBytes;
|
|
973
1481
|
}
|
|
1482
|
+
out.set(meta, offset);
|
|
1483
|
+
return ok(out);
|
|
1484
|
+
} catch (error) {
|
|
974
1485
|
return err(
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
})
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
if (!record(built.value)) {
|
|
984
|
-
return err(
|
|
985
|
-
new ImportError({
|
|
986
|
-
code: "import-internal-error",
|
|
987
|
-
expected: "ScriptablePack build output to be an object keyed by declared sourceKey",
|
|
988
|
-
hint: "return one concrete Asset payload for each declared sourceKey",
|
|
989
|
-
detail: { reason: "build output is not an object" }
|
|
990
|
-
})
|
|
1486
|
+
failure(
|
|
1487
|
+
sourceKey,
|
|
1488
|
+
"valid canonical mesh payload",
|
|
1489
|
+
error instanceof Error ? error.message : String(error)
|
|
1490
|
+
)
|
|
991
1491
|
);
|
|
992
1492
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
if (!isAsset(asset)) {
|
|
1002
|
-
return err(
|
|
1003
|
-
new ImportError({
|
|
1004
|
-
code: "import-internal-error",
|
|
1005
|
-
expected: `a concrete Asset payload for sourceKey ${sourceKey}`,
|
|
1006
|
-
hint: "return a durable Asset with a kind from SCRIPTABLE_PACK_ASSET_KINDS",
|
|
1007
|
-
detail: { reason: "build output payload is missing or has an unknown kind" }
|
|
1008
|
-
})
|
|
1009
|
-
);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/scriptable-pack.ts
|
|
1496
|
+
var AssetOutputProducerRegistry = class {
|
|
1497
|
+
producers = /* @__PURE__ */ new Map();
|
|
1498
|
+
register(producer) {
|
|
1499
|
+
if (producer.kind.trim().length === 0 || producer.version.trim().length === 0) {
|
|
1500
|
+
throw new TypeError("Pack output producer kind and version must be non-empty");
|
|
1010
1501
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
return err({
|
|
1014
|
-
code: "pack-source-output-invalid",
|
|
1015
|
-
expected: `a domain output producer registered for kind ${descriptor.kind}`,
|
|
1016
|
-
hint: "attach the owning producer capability, inspect registration, then rebuild or cold-cook",
|
|
1017
|
-
detail: {
|
|
1018
|
-
missingGuids: [AssetGuid.format(descriptor.guid)],
|
|
1019
|
-
unexpectedSourceKeys: [],
|
|
1020
|
-
kindMismatches: []
|
|
1021
|
-
}
|
|
1022
|
-
});
|
|
1502
|
+
if (typeof producer.produce !== "function") {
|
|
1503
|
+
throw new TypeError(`Pack output producer ${producer.kind} must expose produce`);
|
|
1023
1504
|
}
|
|
1024
|
-
|
|
1025
|
-
guid: AssetGuid.format(descriptor.guid),
|
|
1026
|
-
sourceKey,
|
|
1027
|
-
asset
|
|
1028
|
-
});
|
|
1029
|
-
if (!product2.ok) return err(product2.error);
|
|
1030
|
-
const productError = productContractError(sourceKey, descriptor.kind, product2.value);
|
|
1031
|
-
if (productError !== void 0) return err(productError);
|
|
1032
|
-
assets.push({
|
|
1033
|
-
guid: AssetGuid.format(descriptor.guid),
|
|
1034
|
-
kind: descriptor.kind,
|
|
1035
|
-
...descriptor.name === void 0 ? {} : { name: descriptor.name },
|
|
1036
|
-
payload: product2.value.payload,
|
|
1037
|
-
refs: product2.value.refs,
|
|
1038
|
-
artifacts: product2.value.artifacts
|
|
1039
|
-
});
|
|
1505
|
+
this.producers.set(producer.kind, producer);
|
|
1040
1506
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
)
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
);
|
|
1051
|
-
const closureError2 = externalClosureError(declared, referenced, read);
|
|
1052
|
-
if (closureError2 !== void 0) return err(closureError2);
|
|
1053
|
-
const externalEvidence = [...declared].sort().map((guid) => {
|
|
1054
|
-
const observedRead = observed.reads.get(guid);
|
|
1055
|
-
const isReference = referenced.has(guid);
|
|
1056
|
-
return {
|
|
1057
|
-
guid,
|
|
1058
|
-
usage: observedRead === void 0 ? "reference" : isReference ? "both" : "content",
|
|
1059
|
-
...observedRead === void 0 ? {} : { generation: observedRead.generation, digest: observedRead.digest }
|
|
1060
|
-
};
|
|
1061
|
-
});
|
|
1062
|
-
const fingerprintEvidence = externalEvidence.map(({ guid, usage, digest }) => ({
|
|
1063
|
-
guid,
|
|
1064
|
-
usage,
|
|
1065
|
-
...digest === void 0 ? {} : { digest }
|
|
1066
|
-
}));
|
|
1067
|
-
const inputFingerprint = await fingerprint({
|
|
1068
|
-
meta: projectScriptablePackMeta(options.definition, options.sourcePath),
|
|
1069
|
-
sceneComponents: projectScriptablePackSceneComponents(options.definition.sceneComponents),
|
|
1070
|
-
sourceClosure: stableSourceClosure(options.sourceClosure),
|
|
1071
|
-
externalEvidence: fingerprintEvidence,
|
|
1072
|
-
authoringContractVersion: options.authoringContractVersion,
|
|
1073
|
-
producerVersions: options.outputs.versions()
|
|
1074
|
-
});
|
|
1075
|
-
const refs = assets.flatMap((asset) => asset.refs);
|
|
1076
|
-
const artifacts = Object.fromEntries(
|
|
1077
|
-
assets.flatMap(
|
|
1078
|
-
(asset) => Object.entries(asset.artifacts).map(([key, artifact]) => [`${asset.guid}/${key}`, artifact])
|
|
1079
|
-
)
|
|
1080
|
-
);
|
|
1081
|
-
const product = createImportProduct({
|
|
1082
|
-
assets,
|
|
1083
|
-
sourceDependencies: options.sourceClosure.map((entry) => entry.path),
|
|
1084
|
-
refs,
|
|
1085
|
-
artifacts,
|
|
1086
|
-
receipts: assets.map((asset) => ({
|
|
1087
|
-
guid: asset.guid,
|
|
1088
|
-
origin: "sourceMeta",
|
|
1089
|
-
status: "succeeded",
|
|
1090
|
-
inputFingerprint
|
|
1091
|
-
})),
|
|
1092
|
-
diagnostics: [],
|
|
1093
|
-
sourceRevision: inputFingerprint,
|
|
1094
|
-
sourceKey: options.sourcePath
|
|
1095
|
-
});
|
|
1096
|
-
if (!product.ok) return err(product.error);
|
|
1097
|
-
return ok({
|
|
1098
|
-
product: product.value,
|
|
1099
|
-
stagedOutputs: await Promise.all(
|
|
1100
|
-
Object.keys(options.definition.assets).sort().map(async (sourceKey) => {
|
|
1101
|
-
const descriptor = options.definition.assets[sourceKey];
|
|
1102
|
-
const asset = output[sourceKey];
|
|
1103
|
-
if (descriptor === void 0 || !isAsset(asset)) {
|
|
1104
|
-
throw new Error(`validated ScriptablePack output ${sourceKey} is not an Asset`);
|
|
1105
|
-
}
|
|
1106
|
-
return {
|
|
1107
|
-
guid: descriptor.guid,
|
|
1108
|
-
sourceKey,
|
|
1109
|
-
asset: privateClone(asset),
|
|
1110
|
-
digest: await fingerprint(asset)
|
|
1111
|
-
};
|
|
1112
|
-
})
|
|
1113
|
-
),
|
|
1114
|
-
externalEvidence,
|
|
1115
|
-
inputFingerprint
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1507
|
+
get(kind) {
|
|
1508
|
+
return this.producers.get(kind);
|
|
1509
|
+
}
|
|
1510
|
+
versions() {
|
|
1511
|
+
return Object.fromEntries(
|
|
1512
|
+
[...this.producers.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([kind, producer]) => [kind, producer.version])
|
|
1513
|
+
);
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1118
1516
|
|
|
1119
1517
|
// src/scriptable-pack-output-producers.ts
|
|
1120
1518
|
function producerError(input, reason) {
|
|
@@ -1127,11 +1525,11 @@ function producerError(input, reason) {
|
|
|
1127
1525
|
}
|
|
1128
1526
|
function formatGuid(value) {
|
|
1129
1527
|
if (typeof value === "string") {
|
|
1130
|
-
const parsed = AssetGuid.parse(value);
|
|
1528
|
+
const parsed = AssetGuid$1.parse(value);
|
|
1131
1529
|
if (!parsed.ok) throw parsed.error;
|
|
1132
|
-
return AssetGuid.format(parsed.value);
|
|
1530
|
+
return AssetGuid$1.format(parsed.value);
|
|
1133
1531
|
}
|
|
1134
|
-
return AssetGuid.format(value);
|
|
1532
|
+
return AssetGuid$1.format(value);
|
|
1135
1533
|
}
|
|
1136
1534
|
function canonical(value) {
|
|
1137
1535
|
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
@@ -1143,11 +1541,11 @@ function canonical(value) {
|
|
|
1143
1541
|
function particleProgramArtifact(effect) {
|
|
1144
1542
|
const artifactProgram = { format: effect.program.format, emitters: effect.program.emitters };
|
|
1145
1543
|
const bytes2 = new TextEncoder().encode(canonical(artifactProgram));
|
|
1146
|
-
const
|
|
1544
|
+
const fingerprint = `sha256:${bytesToHex(sha256(bytes2))}`;
|
|
1147
1545
|
return {
|
|
1148
|
-
program: { ...effect.program, fingerprint
|
|
1546
|
+
program: { ...effect.program, fingerprint },
|
|
1149
1547
|
bytes: bytes2,
|
|
1150
|
-
fingerprint
|
|
1548
|
+
fingerprint
|
|
1151
1549
|
};
|
|
1152
1550
|
}
|
|
1153
1551
|
function materialProduct(input) {
|
|
@@ -1214,6 +1612,13 @@ function meshProduct(input) {
|
|
|
1214
1612
|
sourceField: { fieldName: "materialSlots", arrayIndex: slotIndex }
|
|
1215
1613
|
});
|
|
1216
1614
|
}
|
|
1615
|
+
const seenRefs = new Set(refs.map((reference) => reference.guid.toLowerCase()));
|
|
1616
|
+
for (const [lodIndex, lod] of (mesh.lods ?? []).entries()) {
|
|
1617
|
+
const guid = formatGuid(lod.mesh);
|
|
1618
|
+
if (seenRefs.has(guid.toLowerCase())) continue;
|
|
1619
|
+
seenRefs.add(guid.toLowerCase());
|
|
1620
|
+
refs.push({ guid, sourceField: { fieldName: "lods", arrayIndex: lodIndex } });
|
|
1621
|
+
}
|
|
1217
1622
|
return {
|
|
1218
1623
|
payload: mesh,
|
|
1219
1624
|
refs,
|
|
@@ -1254,6 +1659,25 @@ function sceneProduct(input, components) {
|
|
|
1254
1659
|
artifacts: {}
|
|
1255
1660
|
};
|
|
1256
1661
|
}
|
|
1662
|
+
function containsAssetGuid(value) {
|
|
1663
|
+
if (typeof value === "string") return AssetGuid$1.parse(value).ok;
|
|
1664
|
+
if (Array.isArray(value)) return value.some(containsAssetGuid);
|
|
1665
|
+
if (value !== null && typeof value === "object") {
|
|
1666
|
+
return Object.values(value).some(containsAssetGuid);
|
|
1667
|
+
}
|
|
1668
|
+
return false;
|
|
1669
|
+
}
|
|
1670
|
+
function preExternalizedSceneProduct(input) {
|
|
1671
|
+
if (input.asset.kind !== "scene") throw new TypeError("expected SceneAsset");
|
|
1672
|
+
if (containsAssetGuid(input.asset)) {
|
|
1673
|
+
throw new TypeError("direct scene payload must use explicit refs with runtime indices");
|
|
1674
|
+
}
|
|
1675
|
+
return {
|
|
1676
|
+
payload: { ...input.asset, kind: "scene" },
|
|
1677
|
+
refs: [],
|
|
1678
|
+
artifacts: {}
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1257
1681
|
function createSafeProducer(kind, version, product) {
|
|
1258
1682
|
return {
|
|
1259
1683
|
kind,
|
|
@@ -1362,7 +1786,7 @@ function ordinaryPodProduct(input) {
|
|
|
1362
1786
|
case "tileset": {
|
|
1363
1787
|
const tileset = asset;
|
|
1364
1788
|
const refs = tileset.atlases.map((atlas, index) => {
|
|
1365
|
-
const parsed = AssetGuid.parse(atlas);
|
|
1789
|
+
const parsed = AssetGuid$1.parse(atlas);
|
|
1366
1790
|
if (!parsed.ok) throw parsed.error;
|
|
1367
1791
|
return ref(parsed.value, "atlases", index);
|
|
1368
1792
|
});
|
|
@@ -1395,7 +1819,7 @@ function ordinaryPodProduct(input) {
|
|
|
1395
1819
|
}
|
|
1396
1820
|
case "skin": {
|
|
1397
1821
|
const skin = asset;
|
|
1398
|
-
const skeletonGuid = AssetGuid.parse(skin.skeletonGuid);
|
|
1822
|
+
const skeletonGuid = AssetGuid$1.parse(skin.skeletonGuid);
|
|
1399
1823
|
if (!skeletonGuid.ok) throw skeletonGuid.error;
|
|
1400
1824
|
return {
|
|
1401
1825
|
payload: skin,
|
|
@@ -1414,7 +1838,7 @@ function ordinaryPodProduct(input) {
|
|
|
1414
1838
|
const refs = [];
|
|
1415
1839
|
const nodes = graph.nodes.map((node, index) => {
|
|
1416
1840
|
if (node.type !== "clip") return node;
|
|
1417
|
-
const parsed = AssetGuid.parse(node.clip);
|
|
1841
|
+
const parsed = AssetGuid$1.parse(node.clip);
|
|
1418
1842
|
if (!parsed.ok) throw parsed.error;
|
|
1419
1843
|
const referenceIndex = refs.push(ref(parsed.value, "nodes", index)) - 1;
|
|
1420
1844
|
return { ...node, clip: referenceIndex };
|
|
@@ -1455,219 +1879,74 @@ function ordinaryPodProduct(input) {
|
|
|
1455
1879
|
mediaType: "application/json",
|
|
1456
1880
|
assetCodec: { name: "forgeax-vfx-program", version: effect.program.format },
|
|
1457
1881
|
bytes: cooked.bytes
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
};
|
|
1461
|
-
}
|
|
1462
|
-
case "material":
|
|
1463
|
-
case "mesh":
|
|
1464
|
-
case "scene":
|
|
1465
|
-
throw new TypeError(`ordinary producer received already-owned ${asset.kind} asset`);
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
var materialAssetOutputProducer = createSafeProducer(
|
|
1469
|
-
"material",
|
|
1470
|
-
"material-pack/1",
|
|
1471
|
-
materialProduct
|
|
1472
|
-
);
|
|
1473
|
-
var meshAssetOutputProducer = createSafeProducer("mesh", "mesh-binary/4", meshProduct);
|
|
1474
|
-
var textureAssetOutputProducer = createSafeProducer(
|
|
1475
|
-
"texture",
|
|
1476
|
-
"texture-pack/1",
|
|
1477
|
-
textureProduct
|
|
1478
|
-
);
|
|
1479
|
-
function createSceneAssetOutputProducer(sceneComponents = []) {
|
|
1480
|
-
const schemas = new Map(
|
|
1481
|
-
sceneComponents.map((component) => [component.name, component.fields])
|
|
1482
|
-
);
|
|
1483
|
-
return createSafeProducer("scene", "scene-pack/3", (input) => sceneProduct(input, schemas));
|
|
1484
|
-
}
|
|
1485
|
-
function createStandardAssetOutputProducerRegistry(sceneComponents = []) {
|
|
1486
|
-
const registry = new AssetOutputProducerRegistry();
|
|
1487
|
-
registry.register(materialAssetOutputProducer);
|
|
1488
|
-
registry.register(meshAssetOutputProducer);
|
|
1489
|
-
registry.register(textureAssetOutputProducer);
|
|
1490
|
-
registry.register(createSceneAssetOutputProducer(sceneComponents));
|
|
1491
|
-
for (const kind of [
|
|
1492
|
-
"equirect",
|
|
1493
|
-
"sampler",
|
|
1494
|
-
"font",
|
|
1495
|
-
"render-pipeline",
|
|
1496
|
-
"tileset",
|
|
1497
|
-
"video",
|
|
1498
|
-
"skeleton",
|
|
1499
|
-
"skin",
|
|
1500
|
-
"animation-clip",
|
|
1501
|
-
"animation-graph",
|
|
1502
|
-
"audio",
|
|
1503
|
-
"particle-effect"
|
|
1504
|
-
]) {
|
|
1505
|
-
registry.register(createSafeProducer(kind, "ordinary-pod/1", ordinaryPodProduct));
|
|
1506
|
-
}
|
|
1507
|
-
return registry;
|
|
1508
|
-
}
|
|
1509
|
-
function stable2(value) {
|
|
1510
|
-
if (ArrayBuffer.isView(value)) {
|
|
1511
|
-
return `${value.constructor.name}:${JSON.stringify(Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength)))}`;
|
|
1512
|
-
}
|
|
1513
|
-
if (Array.isArray(value)) return `[${value.map(stable2).join(",")}]`;
|
|
1514
|
-
if (value !== null && typeof value === "object") {
|
|
1515
|
-
const record2 = value;
|
|
1516
|
-
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stable2(record2[key])}`).join(",")}}`;
|
|
1517
|
-
}
|
|
1518
|
-
return JSON.stringify(value) ?? "null";
|
|
1519
|
-
}
|
|
1520
|
-
async function assetDigest(asset) {
|
|
1521
|
-
const bytes2 = new TextEncoder().encode(stable2(asset));
|
|
1522
|
-
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes2);
|
|
1523
|
-
return `sha256:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
1524
|
-
}
|
|
1525
|
-
function cycleError(stack, owner, guid) {
|
|
1526
|
-
const cycleStart = stack.indexOf(owner);
|
|
1527
|
-
const cycle = [...stack.slice(cycleStart), owner];
|
|
1528
|
-
return {
|
|
1529
|
-
code: "pack-source-build-cycle",
|
|
1530
|
-
expected: "an acyclic graph of ScriptablePack content dependencies",
|
|
1531
|
-
actual: cycle.join(" -> "),
|
|
1532
|
-
hint: "break one content read edge or convert it to a reference-only dependency",
|
|
1533
|
-
retryable: false,
|
|
1534
|
-
recoveryActions: ["inspect-content-dependency-graph", "edit-source"],
|
|
1535
|
-
detail: { sourcePath: owner, sourceKey: guid, incomingRefs: cycle }
|
|
1536
|
-
};
|
|
1537
|
-
}
|
|
1538
|
-
function missingOutputError(owner, guid) {
|
|
1539
|
-
return {
|
|
1540
|
-
code: "pack-source-output-invalid",
|
|
1541
|
-
expected: `owner ${owner} to stage every declared output including ${guid}`,
|
|
1542
|
-
hint: "return one output for every GUID declared by the staged owner",
|
|
1543
|
-
detail: { missingGuids: [guid], unexpectedSourceKeys: [], kindMismatches: [] }
|
|
1544
|
-
};
|
|
1545
|
-
}
|
|
1546
|
-
function createScriptablePackStagedAssetSnapshotSource(options) {
|
|
1547
|
-
const owners = options.declaredExternalOutputs === void 0 || options.declaredExternalOutputs.length === 0 ? options.owners : [
|
|
1548
|
-
{
|
|
1549
|
-
id: "<declared-pack-external>",
|
|
1550
|
-
guids: options.declaredExternalOutputs.map((output) => output.guid),
|
|
1551
|
-
async build() {
|
|
1552
|
-
return ok(options.declaredExternalOutputs ?? []);
|
|
1553
|
-
}
|
|
1554
|
-
},
|
|
1555
|
-
...options.owners
|
|
1556
|
-
];
|
|
1557
|
-
const ownerByGuid = /* @__PURE__ */ new Map();
|
|
1558
|
-
for (const owner of owners) {
|
|
1559
|
-
if (owner.id.trim().length === 0) throw new TypeError("staged owner id must be non-empty");
|
|
1560
|
-
for (const guid of owner.guids) {
|
|
1561
|
-
const key = AssetGuid.format(guid).toLowerCase();
|
|
1562
|
-
const existing = ownerByGuid.get(key);
|
|
1563
|
-
if (existing !== void 0) {
|
|
1564
|
-
throw new TypeError(`staged GUID ${key} is owned by both ${existing.id} and ${owner.id}`);
|
|
1565
|
-
}
|
|
1566
|
-
ownerByGuid.set(key, owner);
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
const snapshots = /* @__PURE__ */ new Map();
|
|
1570
|
-
const builds = /* @__PURE__ */ new Map();
|
|
1571
|
-
const sourceFor = (stack) => ({
|
|
1572
|
-
async readByGuid(guid) {
|
|
1573
|
-
const key = AssetGuid.format(guid).toLowerCase();
|
|
1574
|
-
const cached = snapshots.get(key);
|
|
1575
|
-
if (cached !== void 0) return ok(structuredClone(cached));
|
|
1576
|
-
const owner = ownerByGuid.get(key);
|
|
1577
|
-
if (owner === void 0) {
|
|
1578
|
-
return err(
|
|
1579
|
-
new AssetError({
|
|
1580
|
-
code: "asset-not-imported",
|
|
1581
|
-
expected: "a staged local owner for the requested GUID",
|
|
1582
|
-
hint: "declare the local ScriptablePack output before rebuilding the generation"
|
|
1583
|
-
})
|
|
1584
|
-
);
|
|
1585
|
-
}
|
|
1586
|
-
if (stack.includes(owner.id)) return err(cycleError(stack, owner.id, key));
|
|
1587
|
-
let building = builds.get(owner.id);
|
|
1588
|
-
if (building === void 0) {
|
|
1589
|
-
building = (async () => {
|
|
1590
|
-
const built2 = await owner.build(sourceFor([...stack, owner.id]));
|
|
1591
|
-
if (!built2.ok) {
|
|
1592
|
-
builds.delete(owner.id);
|
|
1593
|
-
return built2;
|
|
1594
|
-
}
|
|
1595
|
-
const next = /* @__PURE__ */ new Map();
|
|
1596
|
-
for (const output of built2.value) {
|
|
1597
|
-
const outputGuid = AssetGuid.format(output.guid).toLowerCase();
|
|
1598
|
-
if (ownerByGuid.get(outputGuid) !== owner) {
|
|
1599
|
-
builds.delete(owner.id);
|
|
1600
|
-
return err(missingOutputError(owner.id, outputGuid));
|
|
1601
|
-
}
|
|
1602
|
-
next.set(outputGuid, {
|
|
1603
|
-
asset: structuredClone(output.asset),
|
|
1604
|
-
generation: options.generation,
|
|
1605
|
-
digest: output.digest ?? await assetDigest(output.asset)
|
|
1606
|
-
});
|
|
1607
|
-
}
|
|
1608
|
-
for (const declared of owner.guids) {
|
|
1609
|
-
const declaredGuid = AssetGuid.format(declared).toLowerCase();
|
|
1610
|
-
if (!next.has(declaredGuid)) {
|
|
1611
|
-
builds.delete(owner.id);
|
|
1612
|
-
return err(missingOutputError(owner.id, declaredGuid));
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
for (const [outputGuid, snapshot] of next) snapshots.set(outputGuid, snapshot);
|
|
1616
|
-
return ok(void 0);
|
|
1617
|
-
})();
|
|
1618
|
-
builds.set(owner.id, building);
|
|
1619
|
-
}
|
|
1620
|
-
const built = await building;
|
|
1621
|
-
if (!built.ok) return built;
|
|
1622
|
-
const staged = snapshots.get(key);
|
|
1623
|
-
return staged === void 0 ? err(missingOutputError(owner.id, key)) : ok(structuredClone(staged));
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
};
|
|
1624
1885
|
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
const bytes2 = new TextEncoder().encode(`${JSON.stringify(meta)}
|
|
1631
|
-
`);
|
|
1632
|
-
return {
|
|
1633
|
-
...product,
|
|
1634
|
-
assets: product.assets.map(
|
|
1635
|
-
(asset) => asset.guid.toLowerCase() === anchorGuid ? {
|
|
1636
|
-
...asset,
|
|
1886
|
+
case "ies-profile": {
|
|
1887
|
+
const profile = asset;
|
|
1888
|
+
return {
|
|
1889
|
+
payload: profile,
|
|
1890
|
+
refs: [],
|
|
1637
1891
|
artifacts: {
|
|
1638
|
-
|
|
1639
|
-
|
|
1892
|
+
body: {
|
|
1893
|
+
mediaType: "application/octet-stream",
|
|
1894
|
+
assetCodec: { name: "forgeax-ies-profile", version: "1" },
|
|
1895
|
+
bytes: bytes(profile.data)
|
|
1896
|
+
}
|
|
1640
1897
|
}
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
if (!built.ok) return err(built.error);
|
|
1648
|
-
const declaredGuids = Object.values(options.definition.assets).map((descriptor) => AssetGuid.format(descriptor.guid).toLowerCase()).sort();
|
|
1649
|
-
const anchorGuid = declaredGuids[0];
|
|
1650
|
-
if (anchorGuid === void 0) {
|
|
1651
|
-
return err({
|
|
1652
|
-
code: "pack-source-output-invalid",
|
|
1653
|
-
expected: "at least one declared ScriptablePack output",
|
|
1654
|
-
hint: "add an output descriptor before building the package",
|
|
1655
|
-
detail: { missingGuids: [], unexpectedSourceKeys: [], kindMismatches: [] }
|
|
1656
|
-
});
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
case "material":
|
|
1901
|
+
case "mesh":
|
|
1902
|
+
case "scene":
|
|
1903
|
+
throw new TypeError(`ordinary producer received already-owned ${asset.kind} asset`);
|
|
1657
1904
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1905
|
+
}
|
|
1906
|
+
var materialAssetOutputProducer = createSafeProducer(
|
|
1907
|
+
"material",
|
|
1908
|
+
"material-pack/1",
|
|
1909
|
+
materialProduct
|
|
1910
|
+
);
|
|
1911
|
+
var meshAssetOutputProducer = createSafeProducer("mesh", "mesh-binary/4", meshProduct);
|
|
1912
|
+
var textureAssetOutputProducer = createSafeProducer(
|
|
1913
|
+
"texture",
|
|
1914
|
+
"texture-pack/1",
|
|
1915
|
+
textureProduct
|
|
1916
|
+
);
|
|
1917
|
+
function createSceneAssetOutputProducer(sceneComponents = []) {
|
|
1918
|
+
const schemas = new Map(
|
|
1919
|
+
sceneComponents.map((component) => [component.name, component.fields])
|
|
1662
1920
|
);
|
|
1663
|
-
return
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1921
|
+
return createSafeProducer("scene", "scene-pack/3", (input) => sceneProduct(input, schemas));
|
|
1922
|
+
}
|
|
1923
|
+
function createPreExternalizedSceneAssetOutputProducer() {
|
|
1924
|
+
return createSafeProducer("scene", "scene-pack/3", preExternalizedSceneProduct);
|
|
1925
|
+
}
|
|
1926
|
+
function createStandardAssetOutputProducerRegistry(sceneComponents = []) {
|
|
1927
|
+
const registry = new AssetOutputProducerRegistry();
|
|
1928
|
+
registry.register(materialAssetOutputProducer);
|
|
1929
|
+
registry.register(meshAssetOutputProducer);
|
|
1930
|
+
registry.register(textureAssetOutputProducer);
|
|
1931
|
+
registry.register(createSceneAssetOutputProducer(sceneComponents));
|
|
1932
|
+
for (const kind of [
|
|
1933
|
+
"equirect",
|
|
1934
|
+
"sampler",
|
|
1935
|
+
"font",
|
|
1936
|
+
"render-pipeline",
|
|
1937
|
+
"tileset",
|
|
1938
|
+
"video",
|
|
1939
|
+
"skeleton",
|
|
1940
|
+
"skin",
|
|
1941
|
+
"animation-clip",
|
|
1942
|
+
"animation-graph",
|
|
1943
|
+
"audio",
|
|
1944
|
+
"particle-effect",
|
|
1945
|
+
"ies-profile"
|
|
1946
|
+
]) {
|
|
1947
|
+
registry.register(createSafeProducer(kind, "ordinary-pod/1", ordinaryPodProduct));
|
|
1948
|
+
}
|
|
1949
|
+
return registry;
|
|
1671
1950
|
}
|
|
1672
1951
|
function parseProducerReadiness(value) {
|
|
1673
1952
|
if (value === void 0 || value === "before-consume" || value === "on-demand") {
|
|
@@ -1767,25 +2046,517 @@ function canonicalScriptableSourcePath(sourcePath) {
|
|
|
1767
2046
|
const markerIndex = normalized.indexOf(marker);
|
|
1768
2047
|
return markerIndex < 0 ? normalized : normalized.slice(markerIndex + 1);
|
|
1769
2048
|
}
|
|
1770
|
-
function
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
const
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2049
|
+
async function declaredPackExternalOutputs(declarations, cookers = [], requiredGuids = [], externalImport) {
|
|
2050
|
+
if (requiredGuids.length === 0) return [];
|
|
2051
|
+
const required = new Set(requiredGuids.map((guid) => AssetGuid$1.format(guid).toLowerCase()));
|
|
2052
|
+
const available = new Set(required);
|
|
2053
|
+
for (const declaration of declarations.values()) {
|
|
2054
|
+
if (declaration.format !== "meta.json") continue;
|
|
2055
|
+
for (const asset of declaration.value.subAssets) {
|
|
2056
|
+
const parsed = AssetGuid$1.parse(asset.guid);
|
|
2057
|
+
if (!parsed.ok) throw parsed.error;
|
|
2058
|
+
available.add(AssetGuid$1.format(parsed.value).toLowerCase());
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
const outputs = [];
|
|
2062
|
+
for (const declaration of declarations.values()) {
|
|
2063
|
+
if (declaration.format === "meta.json") {
|
|
2064
|
+
if (externalImport === void 0) continue;
|
|
2065
|
+
if (!declaration.value.subAssets.some((asset) => required.has(asset.guid.toLowerCase()))) {
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
const resolved = resolveAssetSource(declaration.sourcePath, declaration.value.source);
|
|
2069
|
+
const meta = {
|
|
2070
|
+
importer: declaration.value.importer,
|
|
2071
|
+
source: resolved,
|
|
2072
|
+
sourceRevision: declaration.sourceRevision,
|
|
2073
|
+
...declaration.value.packageId === void 0 ? {} : { packageId: declaration.value.packageId },
|
|
2074
|
+
...declaration.value.provenance === void 0 ? {} : { provenance: declaration.value.provenance },
|
|
2075
|
+
...declaration.value.revision === void 0 ? {} : { revision: declaration.value.revision },
|
|
2076
|
+
...declaration.value.diagnostics === void 0 ? {} : { diagnostics: declaration.value.diagnostics },
|
|
2077
|
+
importSettings: declaration.value.importSettings,
|
|
2078
|
+
...declaration.value.sourceOverrides === void 0 ? {} : { sourceOverrides: declaration.value.sourceOverrides },
|
|
2079
|
+
subAssets: declaration.value.subAssets.map(({ guid, sourceIndex, sourceKey, kind }) => ({
|
|
2080
|
+
guid,
|
|
2081
|
+
sourceIndex,
|
|
2082
|
+
...sourceKey === void 0 ? {} : { sourceKey },
|
|
2083
|
+
kind
|
|
2084
|
+
})),
|
|
2085
|
+
buildPack: false
|
|
2086
|
+
};
|
|
2087
|
+
const sourcePackage = await produceSourcePackage({
|
|
2088
|
+
meta,
|
|
2089
|
+
registry: externalImport.importerRegistry,
|
|
2090
|
+
fs: externalImport.fsForImport
|
|
2091
|
+
});
|
|
2092
|
+
if (!sourcePackage.ok) {
|
|
2093
|
+
throw new AssetError({
|
|
2094
|
+
code: "asset-not-imported",
|
|
2095
|
+
expected: "the Meta importer to produce the requested dependency",
|
|
2096
|
+
hint: "repair the Meta source and rerun the Pack build",
|
|
2097
|
+
detail: { sourcePath: declaration.sourcePath }
|
|
2098
|
+
});
|
|
2099
|
+
}
|
|
2100
|
+
for (const asset of sourcePackage.value.product.assets) {
|
|
2101
|
+
if (!required.has(asset.guid.toLowerCase())) continue;
|
|
2102
|
+
const parsed = AssetGuid$1.parse(asset.guid);
|
|
2103
|
+
if (!parsed.ok) throw parsed.error;
|
|
2104
|
+
const declared = declaration.value.subAssets.find(
|
|
2105
|
+
(candidate) => candidate.guid.toLowerCase() === asset.guid.toLowerCase()
|
|
2106
|
+
);
|
|
2107
|
+
outputs.push({
|
|
2108
|
+
guid: parsed.value,
|
|
2109
|
+
sourceKey: declared?.sourceKey ?? asset.guid,
|
|
2110
|
+
asset: { ...asset.payload, kind: asset.kind }
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
if (declaration.format !== "pack.json") continue;
|
|
2116
|
+
if (declaration.value.schemaVersion === "3.0.0") {
|
|
2117
|
+
const parsed = parsePackSourceJson(declaration.value);
|
|
2118
|
+
if (!parsed.ok || parsed.value.format !== "direct") continue;
|
|
2119
|
+
const projected = projectDirectPackJson(parsed.value);
|
|
2120
|
+
if (!projected.ok) continue;
|
|
2121
|
+
const prepared = await prepareDirectPackTransport({
|
|
2122
|
+
projected: projected.value,
|
|
2123
|
+
sourcePath: declaration.sourcePath,
|
|
2124
|
+
sourceRevision: declaration.sourceRevision,
|
|
2125
|
+
availableGuids: available,
|
|
2126
|
+
...cookers.length === 0 ? {} : { cookers },
|
|
2127
|
+
policy: {
|
|
2128
|
+
base: "/",
|
|
2129
|
+
packagePath: `assets/${projected.value.packageId}.pack.json`,
|
|
2130
|
+
artifactPath: (assetGuid, key) => `${assetGuid}/${key}.bin`,
|
|
2131
|
+
sink: () => {
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
if (!prepared.ok) throw prepared.error;
|
|
2136
|
+
const cookedByGuid = new Map(
|
|
2137
|
+
prepared.value.finalized.pack.assets.map((asset) => [asset.guid.toLowerCase(), asset])
|
|
2138
|
+
);
|
|
2139
|
+
for (const asset of projected.value.assets) {
|
|
2140
|
+
if (!required.has(asset.guid.toLowerCase())) continue;
|
|
2141
|
+
const parsedGuid = AssetGuid$1.parse(asset.guid);
|
|
2142
|
+
if (!parsedGuid.ok) throw parsedGuid.error;
|
|
2143
|
+
const cooked2 = cookedByGuid.get(asset.guid.toLowerCase());
|
|
2144
|
+
if (cooked2 === void 0) {
|
|
2145
|
+
throw new AssetError({
|
|
2146
|
+
code: "asset-not-imported",
|
|
2147
|
+
expected: "the direct Pack producer to retain every declared output",
|
|
2148
|
+
hint: "repair the direct Pack output and rerun the Pack build",
|
|
2149
|
+
detail: { sourcePath: declaration.sourcePath }
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
outputs.push({
|
|
2153
|
+
guid: parsedGuid.value,
|
|
2154
|
+
sourceKey: asset.sourceKey,
|
|
2155
|
+
asset: { kind: cooked2.kind, ...cooked2.payload }
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
const cooked = await readCookedAuthoredPack(declaration.value, cookers, declaration.sourcePath);
|
|
2161
|
+
for (const asset of cooked?.logicalPackage.assets ?? declaration.value.assets) {
|
|
2162
|
+
if (!required.has(asset.guid.toLowerCase())) continue;
|
|
2163
|
+
const parsedGuid = AssetGuid$1.parse(asset.guid);
|
|
2164
|
+
if (!parsedGuid.ok) throw parsedGuid.error;
|
|
2165
|
+
outputs.push({
|
|
2166
|
+
guid: parsedGuid.value,
|
|
2167
|
+
sourceKey: asset.sourceKey ?? asset.guid,
|
|
2168
|
+
asset: { ...asset.payload, kind: asset.kind }
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
return outputs;
|
|
2173
|
+
}
|
|
2174
|
+
async function readCookedAuthoredPack(authoredPack, cookers = [], sourcePath) {
|
|
2175
|
+
if (authoredPack.schemaVersion !== "2.0.0") return void 0;
|
|
2176
|
+
const registry = new NativeCookerRegistry();
|
|
2177
|
+
for (const cooker of cookers) registry.register(cooker);
|
|
2178
|
+
const assets = [];
|
|
2179
|
+
const refsByGuid = /* @__PURE__ */ new Map();
|
|
2180
|
+
let hasCookedAsset = false;
|
|
2181
|
+
for (const asset of authoredPack.assets) {
|
|
2182
|
+
if (asset.execution !== "cooked") {
|
|
2183
|
+
assets.push({
|
|
2184
|
+
guid: asset.guid,
|
|
2185
|
+
kind: asset.kind,
|
|
2186
|
+
...asset.name === void 0 ? {} : { name: asset.name },
|
|
2187
|
+
payload: asset.payload,
|
|
2188
|
+
refs: asset.refs,
|
|
2189
|
+
artifacts: {}
|
|
2190
|
+
});
|
|
2191
|
+
continue;
|
|
2192
|
+
}
|
|
2193
|
+
if (isEngineOwnedMaterial(asset)) {
|
|
2194
|
+
assets.push({
|
|
2195
|
+
guid: asset.guid,
|
|
2196
|
+
kind: asset.kind,
|
|
2197
|
+
...asset.name === void 0 ? {} : { name: asset.name },
|
|
2198
|
+
payload: asset.payload,
|
|
2199
|
+
refs: asset.refs,
|
|
2200
|
+
artifacts: {}
|
|
2201
|
+
});
|
|
2202
|
+
continue;
|
|
2203
|
+
}
|
|
2204
|
+
hasCookedAsset = true;
|
|
2205
|
+
const result = await registry.runDraft(asset.kind, {
|
|
2206
|
+
guid: asset.guid,
|
|
2207
|
+
// Pack v2 stores the asset kind beside payload. Native producer APIs
|
|
2208
|
+
// consume the runtime Asset shape, so reconstruct that one boundary
|
|
2209
|
+
// field before invoking the cooker.
|
|
2210
|
+
source: nativeCookSource(asset),
|
|
2211
|
+
...asset.sourceKey === void 0 ? {} : { sourceKey: asset.sourceKey },
|
|
2212
|
+
...sourcePath === void 0 ? {} : { sourcePath },
|
|
2213
|
+
refs: asset.refs
|
|
2214
|
+
});
|
|
2215
|
+
if (!result.ok) throw result.error;
|
|
2216
|
+
const draft = result.value;
|
|
2217
|
+
refsByGuid.set(asset.guid.toLowerCase(), [...draft.refs]);
|
|
2218
|
+
assets.push({
|
|
2219
|
+
guid: draft.guid,
|
|
2220
|
+
kind: asset.kind,
|
|
2221
|
+
...asset.name === void 0 ? {} : { name: asset.name },
|
|
2222
|
+
payload: draft.payload,
|
|
2223
|
+
refs: [...draft.refs],
|
|
2224
|
+
artifacts: draft.artifacts
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
return hasCookedAsset ? {
|
|
2228
|
+
logicalPackage: { assets },
|
|
2229
|
+
refsByGuid
|
|
2230
|
+
} : void 0;
|
|
2231
|
+
}
|
|
2232
|
+
function directReference(guid) {
|
|
2233
|
+
return { guid, sourceField: { fieldName: "refs" } };
|
|
2234
|
+
}
|
|
2235
|
+
function mergeDirectReferences(produced, declared) {
|
|
2236
|
+
const merged = [...produced];
|
|
2237
|
+
const seen = new Set(produced.map((reference) => reference.guid.toLowerCase()));
|
|
2238
|
+
for (const guid of declared) {
|
|
2239
|
+
const parsed = AssetGuid$1.parse(guid);
|
|
2240
|
+
if (!parsed.ok) throw parsed.error;
|
|
2241
|
+
const normalized = AssetGuid$1.format(parsed.value);
|
|
2242
|
+
if (seen.has(normalized.toLowerCase())) continue;
|
|
2243
|
+
seen.add(normalized.toLowerCase());
|
|
2244
|
+
merged.push(directReference(normalized));
|
|
2245
|
+
}
|
|
2246
|
+
return merged;
|
|
2247
|
+
}
|
|
2248
|
+
function directReferenceFailure(sourcePath, guids) {
|
|
2249
|
+
return {
|
|
2250
|
+
code: "pack-output-reference-missing",
|
|
2251
|
+
expected: "every direct Pack reference to resolve to a local or published AssetGuid",
|
|
2252
|
+
hint: "publish the referenced Pack or repair the direct refs before rebuilding the Pack",
|
|
2253
|
+
detail: { sourcePath, guids: [...guids].sort() }
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
function directInputFingerprint(sourceRevision, nativeFingerprints) {
|
|
2257
|
+
if (nativeFingerprints.size === 0) return sourceRevision;
|
|
2258
|
+
return `sha256:${packageTransportRevision({
|
|
2259
|
+
sourceRevision,
|
|
2260
|
+
nativeCookers: [...nativeFingerprints.entries()].sort(
|
|
2261
|
+
([left], [right]) => left.localeCompare(right)
|
|
2262
|
+
)
|
|
2263
|
+
})}`;
|
|
2264
|
+
}
|
|
2265
|
+
function importedAssetArtifacts(assets) {
|
|
2266
|
+
return Object.fromEntries(
|
|
2267
|
+
assets.flatMap(
|
|
2268
|
+
(asset) => Object.entries(asset.artifacts).map(([key, artifact]) => [`${asset.guid}/${key}`, artifact])
|
|
2269
|
+
)
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2272
|
+
function rawDirectProduct(input) {
|
|
2273
|
+
const inputFingerprint = `sha256:${packageTransportRevision({
|
|
2274
|
+
packageId: input.projected.packageId,
|
|
2275
|
+
sourceRevision: input.sourceRevision,
|
|
2276
|
+
assets: input.projected.assets
|
|
2277
|
+
})}`;
|
|
2278
|
+
const assets = input.projected.assets.map((asset) => ({
|
|
2279
|
+
guid: asset.guid,
|
|
2280
|
+
kind: asset.kind,
|
|
2281
|
+
...asset.name === void 0 ? {} : { name: asset.name },
|
|
2282
|
+
payload: directRuntimePayload(asset),
|
|
2283
|
+
refs: asset.refs.map(directReference),
|
|
2284
|
+
artifacts: {}
|
|
2285
|
+
}));
|
|
2286
|
+
return {
|
|
2287
|
+
product: {
|
|
2288
|
+
assets,
|
|
2289
|
+
sourceDependencies: [input.sourcePath],
|
|
2290
|
+
refs: assets.flatMap((asset) => asset.refs),
|
|
2291
|
+
artifacts: importedAssetArtifacts(assets),
|
|
2292
|
+
receipts: assets.map((asset) => ({
|
|
2293
|
+
guid: asset.guid,
|
|
2294
|
+
origin: "authoredPack",
|
|
2295
|
+
status: "succeeded",
|
|
2296
|
+
inputFingerprint
|
|
2297
|
+
})),
|
|
2298
|
+
diagnostics: [],
|
|
2299
|
+
sourceRevision: inputFingerprint,
|
|
2300
|
+
sourceKey: input.sourcePath
|
|
2301
|
+
},
|
|
2302
|
+
stagedOutputs: input.projected.assets.map((asset) => ({
|
|
2303
|
+
guid: directGuid(asset.guid),
|
|
2304
|
+
sourceKey: asset.sourceKey,
|
|
2305
|
+
asset: {
|
|
2306
|
+
...directRuntimePayload(asset),
|
|
2307
|
+
kind: asset.kind
|
|
2308
|
+
},
|
|
2309
|
+
digest: `sha256:${packageTransportRevision({ kind: asset.kind, payload: asset.payload })}`
|
|
2310
|
+
})),
|
|
2311
|
+
externalEvidence: [],
|
|
2312
|
+
inputFingerprint
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
function directGuid(value) {
|
|
2316
|
+
const parsed = AssetGuid$1.parse(value);
|
|
2317
|
+
if (!parsed.ok) throw parsed.error;
|
|
2318
|
+
return parsed.value;
|
|
2319
|
+
}
|
|
2320
|
+
function nativeRefs(refs) {
|
|
2321
|
+
return refs.map((guid) => {
|
|
2322
|
+
const parsed = AssetGuid$1.parse(guid);
|
|
2323
|
+
if (!parsed.ok) throw parsed.error;
|
|
2324
|
+
return { guid: AssetGuid$1.format(parsed.value) };
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
function nativeCookSource(asset) {
|
|
2328
|
+
if (asset.kind !== "material" || asset.payload === null || typeof asset.payload !== "object" || Array.isArray(asset.payload)) {
|
|
2329
|
+
return asset.payload;
|
|
2330
|
+
}
|
|
2331
|
+
return { ...asset.payload, kind: asset.kind };
|
|
2332
|
+
}
|
|
2333
|
+
function isEngineOwnedMaterial(asset) {
|
|
2334
|
+
if (asset.kind !== "material" || asset.payload === null || typeof asset.payload !== "object" || Array.isArray(asset.payload)) {
|
|
2335
|
+
return false;
|
|
2336
|
+
}
|
|
2337
|
+
return isEngineMaterial(asset.payload);
|
|
2338
|
+
}
|
|
2339
|
+
function directRuntimePayload(asset) {
|
|
2340
|
+
if (asset.kind !== "ui" || asset.payload === null || typeof asset.payload !== "object" || Array.isArray(asset.payload)) {
|
|
2341
|
+
return asset.payload;
|
|
2342
|
+
}
|
|
2343
|
+
return { ...asset.payload, guid: asset.guid };
|
|
2344
|
+
}
|
|
2345
|
+
function directAssetForProducer(asset) {
|
|
2346
|
+
const payload = {
|
|
2347
|
+
...directRuntimePayload(asset),
|
|
2348
|
+
kind: asset.kind
|
|
2349
|
+
};
|
|
2350
|
+
if (asset.kind !== "mesh") return payload;
|
|
2351
|
+
return normalizeMeshPayload(payload, asset.refs) ?? payload;
|
|
2352
|
+
}
|
|
2353
|
+
async function prepareDirectPackTransport(input) {
|
|
2354
|
+
const localGuids = new Set(input.projected.assets.map((asset) => asset.guid.toLowerCase()));
|
|
2355
|
+
const availableGuids = new Set(
|
|
2356
|
+
[...input.availableGuids ?? [], ...BUILTIN_MESH_ASSETS.map((asset) => asset.guid)].filter(
|
|
2357
|
+
(guid) => !localGuids.has(guid.toLowerCase())
|
|
2358
|
+
)
|
|
2359
|
+
);
|
|
2360
|
+
const directArtifacts = input.projected.assets.find(
|
|
2361
|
+
(asset) => asset.artifacts !== void 0 && Object.keys(asset.artifacts).length > 0
|
|
2362
|
+
);
|
|
2363
|
+
if (directArtifacts !== void 0) {
|
|
2364
|
+
return err({
|
|
2365
|
+
code: "pack-parameter-invalid",
|
|
2366
|
+
expected: "direct v3 authoring entries to leave artifacts empty for the producer",
|
|
2367
|
+
hint: "remove authored artifact data and let the registered Asset producer create it",
|
|
2368
|
+
detail: { sourcePath: input.sourcePath, sourceKey: directArtifacts.sourceKey }
|
|
2369
|
+
});
|
|
2370
|
+
}
|
|
2371
|
+
const packageId = PackageId$1.parse(input.projected.packageId);
|
|
2372
|
+
if (!packageId.ok) return err(packageId.error);
|
|
2373
|
+
const cookerRegistry = new NativeCookerRegistry();
|
|
2374
|
+
for (const cooker of input.cookers ?? []) cookerRegistry.register(cooker);
|
|
2375
|
+
const nativeDrafts = /* @__PURE__ */ new Map();
|
|
2376
|
+
const nativeFingerprints = /* @__PURE__ */ new Map();
|
|
2377
|
+
for (const asset of input.projected.assets) {
|
|
2378
|
+
if (!isScriptablePackAssetKind(asset.kind)) continue;
|
|
2379
|
+
if (cookerRegistry.get(asset.kind) === void 0) continue;
|
|
2380
|
+
if (isEngineOwnedMaterial(asset)) continue;
|
|
2381
|
+
const draft = await cookerRegistry.runDraft(asset.kind, {
|
|
2382
|
+
guid: asset.guid,
|
|
2383
|
+
// Direct v3 entries keep `kind` at the entry boundary. Reattach it for
|
|
2384
|
+
// producer contracts such as MaterialAsset, whose payload is otherwise
|
|
2385
|
+
// intentionally allowed to omit the discriminant.
|
|
2386
|
+
source: nativeCookSource(asset),
|
|
2387
|
+
sourceKey: asset.sourceKey,
|
|
2388
|
+
sourcePath: input.sourcePath,
|
|
2389
|
+
refs: asset.refs
|
|
2390
|
+
});
|
|
2391
|
+
if (!draft.ok) return err(draft.error);
|
|
2392
|
+
if (draft.value.guid.toLowerCase() !== asset.guid.toLowerCase()) {
|
|
2393
|
+
return err({
|
|
2394
|
+
code: "pack-parameter-invalid",
|
|
2395
|
+
expected: "a direct Pack cooker to preserve the derived AssetGuid",
|
|
2396
|
+
hint: "repair the native cooker output GUID and rebuild the direct Pack",
|
|
2397
|
+
detail: {
|
|
2398
|
+
sourcePath: input.sourcePath,
|
|
2399
|
+
sourceKey: asset.sourceKey,
|
|
2400
|
+
expectedGuid: asset.guid,
|
|
2401
|
+
actualGuid: draft.value.guid
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
}
|
|
2405
|
+
nativeDrafts.set(asset.guid.toLowerCase(), draft.value);
|
|
2406
|
+
nativeFingerprints.set(asset.sourceKey, draft.value.inputFingerprint);
|
|
2407
|
+
}
|
|
2408
|
+
const unsupported = input.projected.assets.filter(
|
|
2409
|
+
(asset) => !isScriptablePackAssetKind(asset.kind)
|
|
2410
|
+
);
|
|
2411
|
+
if (unsupported.length > 0 && unsupported.length !== input.projected.assets.length) {
|
|
2412
|
+
return err({
|
|
2413
|
+
code: "pack-parameter-invalid",
|
|
2414
|
+
expected: "a direct Pack to contain only producer-backed Engine Assets or only direct PODs",
|
|
2415
|
+
hint: "split custom direct PODs from producer-backed Assets into separate Packs",
|
|
2416
|
+
detail: {
|
|
2417
|
+
sourcePath: input.sourcePath,
|
|
2418
|
+
unsupportedKinds: [...new Set(unsupported.map((asset) => asset.kind))].sort()
|
|
2419
|
+
}
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
if (unsupported.length === input.projected.assets.length) {
|
|
2423
|
+
const raw = rawDirectProduct(input);
|
|
2424
|
+
const known2 = /* @__PURE__ */ new Set([...availableGuids, ...localGuids]);
|
|
2425
|
+
const missing2 = /* @__PURE__ */ new Set();
|
|
2426
|
+
for (const asset of raw.product.assets) {
|
|
2427
|
+
for (const reference of asset.refs) {
|
|
2428
|
+
if (!known2.has(reference.guid.toLowerCase())) missing2.add(reference.guid.toLowerCase());
|
|
1785
2429
|
}
|
|
1786
|
-
|
|
2430
|
+
}
|
|
2431
|
+
if (missing2.size > 0) return err(directReferenceFailure(input.sourcePath, [...missing2]));
|
|
2432
|
+
const finalized2 = await finalizePackageTransportSource(
|
|
2433
|
+
projectImportProductForBuild(raw.product),
|
|
2434
|
+
input.policy
|
|
2435
|
+
);
|
|
2436
|
+
const facts2 = projectScriptablePackPublication(raw);
|
|
2437
|
+
if (!facts2.ok) return facts2;
|
|
2438
|
+
const displaySourcePath2 = input.displaySourcePath ?? input.sourcePath;
|
|
2439
|
+
const revision2 = await scriptablePackResourceRevision(displaySourcePath2, raw.inputFingerprint, [
|
|
2440
|
+
{ path: input.sourcePath, digest: input.sourceRevision }
|
|
2441
|
+
]);
|
|
2442
|
+
return ok({
|
|
2443
|
+
projected: input.projected,
|
|
2444
|
+
product: raw,
|
|
2445
|
+
finalized: finalized2,
|
|
2446
|
+
facts: facts2.value,
|
|
2447
|
+
revision: revision2
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
const definition = {
|
|
2451
|
+
schemaVersion: "2.0.0",
|
|
2452
|
+
packageId: packageId.value,
|
|
2453
|
+
build: () => ok(
|
|
2454
|
+
Object.fromEntries(
|
|
2455
|
+
input.projected.assets.map((asset) => [
|
|
2456
|
+
asset.sourceKey,
|
|
2457
|
+
{
|
|
2458
|
+
...nativeDrafts.get(asset.guid.toLowerCase())?.payload ?? directAssetForProducer(asset),
|
|
2459
|
+
kind: asset.kind
|
|
2460
|
+
}
|
|
2461
|
+
])
|
|
2462
|
+
)
|
|
2463
|
+
)
|
|
2464
|
+
};
|
|
2465
|
+
const outputs = createStandardAssetOutputProducerRegistry();
|
|
2466
|
+
outputs.register(createPreExternalizedSceneAssetOutputProducer());
|
|
2467
|
+
const built = await buildScriptablePack({
|
|
2468
|
+
definition,
|
|
2469
|
+
sourcePath: input.sourcePath,
|
|
2470
|
+
outputs,
|
|
2471
|
+
sourceClosure: [{ path: input.sourcePath, digest: input.sourceRevision }],
|
|
2472
|
+
availableGuids,
|
|
2473
|
+
deferReferenceValidation: true
|
|
2474
|
+
});
|
|
2475
|
+
if (!built.ok) return built;
|
|
2476
|
+
const declaredByGuid = new Map(
|
|
2477
|
+
input.projected.assets.map((asset) => [asset.guid.toLowerCase(), asset.refs])
|
|
2478
|
+
);
|
|
2479
|
+
const assets = built.value.product.assets.map((asset) => ({
|
|
2480
|
+
...asset,
|
|
2481
|
+
...nativeDrafts.has(asset.guid.toLowerCase()) ? {
|
|
2482
|
+
payload: nativeDrafts.get(asset.guid.toLowerCase())?.payload,
|
|
2483
|
+
refs: mergeDirectReferences(
|
|
2484
|
+
nativeRefs(nativeDrafts.get(asset.guid.toLowerCase())?.refs ?? []),
|
|
2485
|
+
declaredByGuid.get(asset.guid.toLowerCase()) ?? []
|
|
2486
|
+
),
|
|
2487
|
+
artifacts: nativeDrafts.get(asset.guid.toLowerCase())?.artifacts ?? {}
|
|
2488
|
+
} : {
|
|
2489
|
+
refs: mergeDirectReferences(
|
|
2490
|
+
asset.refs,
|
|
2491
|
+
declaredByGuid.get(asset.guid.toLowerCase()) ?? []
|
|
2492
|
+
)
|
|
2493
|
+
}
|
|
2494
|
+
}));
|
|
2495
|
+
const missing = /* @__PURE__ */ new Set();
|
|
2496
|
+
const known = /* @__PURE__ */ new Set([...availableGuids, ...localGuids]);
|
|
2497
|
+
for (const asset of assets) {
|
|
2498
|
+
for (const reference of asset.refs) {
|
|
2499
|
+
if (!known.has(reference.guid.toLowerCase())) missing.add(reference.guid.toLowerCase());
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
if (missing.size > 0) return err(directReferenceFailure(input.sourcePath, [...missing]));
|
|
2503
|
+
const inputFingerprint = directInputFingerprint(built.value.inputFingerprint, nativeFingerprints);
|
|
2504
|
+
const stagedOutputs = input.projected.assets.map((asset) => ({
|
|
2505
|
+
guid: directGuid(asset.guid),
|
|
2506
|
+
sourceKey: asset.sourceKey,
|
|
2507
|
+
asset: directAssetForProducer(asset),
|
|
2508
|
+
digest: `sha256:${packageTransportRevision({ kind: asset.kind, payload: asset.payload })}`
|
|
2509
|
+
}));
|
|
2510
|
+
const product = {
|
|
2511
|
+
...built.value,
|
|
2512
|
+
inputFingerprint,
|
|
2513
|
+
stagedOutputs,
|
|
2514
|
+
product: {
|
|
2515
|
+
...built.value.product,
|
|
2516
|
+
assets,
|
|
2517
|
+
refs: assets.flatMap((asset) => asset.refs),
|
|
2518
|
+
artifacts: importedAssetArtifacts(assets),
|
|
2519
|
+
receipts: built.value.product.receipts.map((receipt) => ({
|
|
2520
|
+
...receipt,
|
|
2521
|
+
inputFingerprint
|
|
2522
|
+
})),
|
|
2523
|
+
sourceRevision: inputFingerprint
|
|
2524
|
+
}
|
|
2525
|
+
};
|
|
2526
|
+
const finalized = await finalizePackageTransportSource(
|
|
2527
|
+
projectImportProductForBuild(product.product),
|
|
2528
|
+
input.policy
|
|
2529
|
+
);
|
|
2530
|
+
const facts = projectScriptablePackPublication(product);
|
|
2531
|
+
if (!facts.ok) return facts;
|
|
2532
|
+
const displaySourcePath = input.displaySourcePath ?? input.sourcePath;
|
|
2533
|
+
const revision = await scriptablePackResourceRevision(
|
|
2534
|
+
displaySourcePath,
|
|
2535
|
+
product.inputFingerprint,
|
|
2536
|
+
[{ path: input.sourcePath, digest: input.sourceRevision }]
|
|
2537
|
+
);
|
|
2538
|
+
return ok({
|
|
2539
|
+
projected: input.projected,
|
|
2540
|
+
product,
|
|
2541
|
+
finalized,
|
|
2542
|
+
facts: facts.value,
|
|
2543
|
+
revision
|
|
1787
2544
|
});
|
|
1788
2545
|
}
|
|
2546
|
+
async function prepareLegacyPackTransport(authoredPack, cookers, policyFor, sourcePath) {
|
|
2547
|
+
const firstGuid = authoredPack.assets[0]?.guid?.toLowerCase();
|
|
2548
|
+
if (authoredPack.schemaVersion !== "2.0.0" || firstGuid === void 0) {
|
|
2549
|
+
return { pack: authoredPack, ...firstGuid === void 0 ? {} : { firstGuid } };
|
|
2550
|
+
}
|
|
2551
|
+
const cooked = await readCookedAuthoredPack(authoredPack, cookers, sourcePath);
|
|
2552
|
+
if (cooked === void 0) return { pack: authoredPack, firstGuid };
|
|
2553
|
+
return {
|
|
2554
|
+
pack: authoredPack,
|
|
2555
|
+
firstGuid,
|
|
2556
|
+
cooked,
|
|
2557
|
+
finalized: await finalizePackageTransportSource(cooked.logicalPackage, policyFor(firstGuid))
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
1789
2560
|
async function materializePreparedScriptablePack(prepared, paths, sink) {
|
|
1790
2561
|
const { product, finalized } = prepared;
|
|
1791
2562
|
await sink.writePackage(paths.packagePath, JSON.stringify(finalized.pack));
|
|
@@ -1797,188 +2568,39 @@ async function materializePreparedScriptablePack(prepared, paths, sink) {
|
|
|
1797
2568
|
);
|
|
1798
2569
|
}
|
|
1799
2570
|
const receipts = /* @__PURE__ */ new Map();
|
|
1800
|
-
for (const
|
|
1801
|
-
const path = paths.receiptPath(guid);
|
|
2571
|
+
for (const asset of product.product.assets) {
|
|
2572
|
+
const path = paths.receiptPath(asset.guid);
|
|
1802
2573
|
await sink.writeReceipt(
|
|
1803
2574
|
path,
|
|
1804
2575
|
JSON.stringify({
|
|
1805
|
-
guid,
|
|
2576
|
+
guid: asset.guid,
|
|
1806
2577
|
origin: "sourceMeta",
|
|
1807
2578
|
status: "succeeded",
|
|
1808
2579
|
inputFingerprint: product.inputFingerprint,
|
|
1809
2580
|
outputDigest: finalized.digest
|
|
1810
2581
|
})
|
|
1811
2582
|
);
|
|
1812
|
-
receipts.set(guid, path);
|
|
2583
|
+
receipts.set(asset.guid.toLowerCase(), path);
|
|
1813
2584
|
}
|
|
1814
2585
|
return receipts;
|
|
1815
2586
|
}
|
|
1816
|
-
async function readCookedAuthoredPack(authoredPack, cookers = [], sourcePath) {
|
|
1817
|
-
const parsed = upgradeLegacyAuthoredPack(authoredPack);
|
|
1818
|
-
if (parsed.schemaVersion !== "2.0.0" || parsed.assets === void 0) return void 0;
|
|
1819
|
-
const registry = new NativeCookerRegistry();
|
|
1820
|
-
for (const cooker of cookers) registry.register(cooker);
|
|
1821
|
-
const assets = [];
|
|
1822
|
-
const refsByGuid = /* @__PURE__ */ new Map();
|
|
1823
|
-
let hasCookedAsset = false;
|
|
1824
|
-
for (const asset of parsed.assets) {
|
|
1825
|
-
const shouldCook = asset.execution === "cooked";
|
|
1826
|
-
if (!shouldCook) {
|
|
1827
|
-
assets.push({
|
|
1828
|
-
guid: asset.guid,
|
|
1829
|
-
kind: asset.kind,
|
|
1830
|
-
...asset.name === void 0 ? {} : { name: asset.name },
|
|
1831
|
-
...asset.sourceKey === void 0 ? {} : { sourceKey: asset.sourceKey },
|
|
1832
|
-
...asset.sourceIndex === void 0 ? {} : { sourceIndex: asset.sourceIndex },
|
|
1833
|
-
...asset.relations === void 0 ? {} : { relations: asset.relations },
|
|
1834
|
-
payload: asset.payload,
|
|
1835
|
-
refs: asset.refs ?? [],
|
|
1836
|
-
artifacts: {}
|
|
1837
|
-
});
|
|
1838
|
-
continue;
|
|
1839
|
-
}
|
|
1840
|
-
hasCookedAsset = true;
|
|
1841
|
-
const result = await registry.runDraft(asset.kind, {
|
|
1842
|
-
guid: asset.guid,
|
|
1843
|
-
source: asset.payload,
|
|
1844
|
-
...asset.sourceKey === void 0 ? {} : { sourceKey: asset.sourceKey },
|
|
1845
|
-
...sourcePath === void 0 ? {} : { sourcePath },
|
|
1846
|
-
refs: asset.refs ?? []
|
|
1847
|
-
});
|
|
1848
|
-
if (!result.ok) throw result.error;
|
|
1849
|
-
const draft = result.value;
|
|
1850
|
-
const refs = [...draft.refs];
|
|
1851
|
-
refsByGuid.set(asset.guid.toLowerCase(), refs);
|
|
1852
|
-
assets.push({
|
|
1853
|
-
guid: draft.guid,
|
|
1854
|
-
kind: asset.kind,
|
|
1855
|
-
...asset.name === void 0 ? {} : { name: asset.name },
|
|
1856
|
-
...asset.sourceKey === void 0 ? {} : { sourceKey: asset.sourceKey },
|
|
1857
|
-
...asset.sourceIndex === void 0 ? {} : { sourceIndex: asset.sourceIndex },
|
|
1858
|
-
...asset.relations === void 0 ? {} : { relations: asset.relations },
|
|
1859
|
-
payload: draft.payload,
|
|
1860
|
-
refs,
|
|
1861
|
-
artifacts: draft.artifacts
|
|
1862
|
-
});
|
|
1863
|
-
}
|
|
1864
|
-
return hasCookedAsset ? {
|
|
1865
|
-
logicalPackage: { schemaVersion: "2.0.0", kind: "internal-text-package", assets },
|
|
1866
|
-
refsByGuid
|
|
1867
|
-
} : void 0;
|
|
1868
|
-
}
|
|
1869
|
-
async function declaredPackExternalOutputs(declarations, cookers = [], requiredGuids = [], externalImport) {
|
|
1870
|
-
if (requiredGuids.length === 0) return [];
|
|
1871
|
-
const required = new Set(requiredGuids.map((guid) => AssetGuid.format(guid).toLowerCase()));
|
|
1872
|
-
const outputs = [];
|
|
1873
|
-
for (const declaration of declarations.values()) {
|
|
1874
|
-
if (declaration.format === "meta.json") {
|
|
1875
|
-
if (externalImport === void 0) continue;
|
|
1876
|
-
if (!declaration.value.subAssets.some((asset) => required.has(asset.guid.toLowerCase()))) {
|
|
1877
|
-
continue;
|
|
1878
|
-
}
|
|
1879
|
-
const assetPaths = externalImport.assetPaths ?? loadAssetConfig(process.cwd()).paths;
|
|
1880
|
-
const resolved = resolveAssetSource(
|
|
1881
|
-
declaration.sourcePath,
|
|
1882
|
-
declaration.value.source,
|
|
1883
|
-
assetPaths
|
|
1884
|
-
);
|
|
1885
|
-
if (!resolved.ok) {
|
|
1886
|
-
throw new AssetError({
|
|
1887
|
-
code: "asset-not-imported",
|
|
1888
|
-
expected: `a resolvable source for Meta dependency ${declaration.sourcePath}`,
|
|
1889
|
-
hint: "repair the Meta source path before rebuilding the ScriptablePack"
|
|
1890
|
-
});
|
|
1891
|
-
}
|
|
1892
|
-
const meta = {
|
|
1893
|
-
importer: declaration.value.importer,
|
|
1894
|
-
source: resolved.value,
|
|
1895
|
-
sourceRevision: declaration.sourceRevision,
|
|
1896
|
-
...declaration.value.packageId === void 0 ? {} : { packageId: declaration.value.packageId },
|
|
1897
|
-
...declaration.value.provenance === void 0 ? {} : { provenance: declaration.value.provenance },
|
|
1898
|
-
...declaration.value.revision === void 0 ? {} : { revision: declaration.value.revision },
|
|
1899
|
-
...declaration.value.diagnostics === void 0 ? {} : { diagnostics: declaration.value.diagnostics },
|
|
1900
|
-
importSettings: declaration.value.importSettings,
|
|
1901
|
-
...declaration.value.sourceOverrides === void 0 ? {} : { sourceOverrides: declaration.value.sourceOverrides },
|
|
1902
|
-
subAssets: declaration.value.subAssets.map(({ guid, sourceIndex, sourceKey, kind }) => ({
|
|
1903
|
-
guid,
|
|
1904
|
-
sourceIndex,
|
|
1905
|
-
...sourceKey === void 0 ? {} : { sourceKey },
|
|
1906
|
-
kind
|
|
1907
|
-
})),
|
|
1908
|
-
buildPack: false
|
|
1909
|
-
};
|
|
1910
|
-
const sourcePackage = await produceSourcePackage({
|
|
1911
|
-
meta,
|
|
1912
|
-
registry: externalImport.importerRegistry,
|
|
1913
|
-
fs: externalImport.fsForImport
|
|
1914
|
-
});
|
|
1915
|
-
if (!sourcePackage.ok) {
|
|
1916
|
-
throw new AssetError({
|
|
1917
|
-
code: "asset-not-imported",
|
|
1918
|
-
expected: `the ${declaration.value.importer} importer to produce Meta dependency outputs`,
|
|
1919
|
-
hint: `repair ${declaration.sourcePath} before rebuilding the ScriptablePack`
|
|
1920
|
-
});
|
|
1921
|
-
}
|
|
1922
|
-
for (const asset of sourcePackage.value.product.assets) {
|
|
1923
|
-
const key = asset.guid.toLowerCase();
|
|
1924
|
-
if (!required.has(key)) continue;
|
|
1925
|
-
const parsed = AssetGuid.parse(asset.guid);
|
|
1926
|
-
if (!parsed.ok) throw parsed.error;
|
|
1927
|
-
outputs.push({
|
|
1928
|
-
guid: parsed.value,
|
|
1929
|
-
asset: { kind: asset.kind, ...asset.payload }
|
|
1930
|
-
});
|
|
1931
|
-
}
|
|
1932
|
-
continue;
|
|
1933
|
-
}
|
|
1934
|
-
if (declaration.format !== "pack.json") continue;
|
|
1935
|
-
const declaredAssets = declaration.value.assets.filter(
|
|
1936
|
-
(asset) => required.has(asset.guid.toLowerCase())
|
|
1937
|
-
);
|
|
1938
|
-
if (declaredAssets.length === 0) continue;
|
|
1939
|
-
const cooked = await readCookedAuthoredPack(declaration.value, cookers, declaration.sourcePath);
|
|
1940
|
-
for (const asset of cooked?.logicalPackage.assets.filter(
|
|
1941
|
-
(item) => required.has(item.guid.toLowerCase())
|
|
1942
|
-
) ?? declaredAssets) {
|
|
1943
|
-
const parsed = AssetGuid.parse(asset.guid);
|
|
1944
|
-
if (!parsed.ok) throw parsed.error;
|
|
1945
|
-
outputs.push({ guid: parsed.value, asset: { kind: asset.kind, ...asset.payload } });
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
return outputs;
|
|
1949
|
-
}
|
|
1950
|
-
async function prepareAuthoredPackTransport(authoredPack, cookers, policyFor, sourcePath) {
|
|
1951
|
-
const pack = upgradeLegacyAuthoredPack(authoredPack);
|
|
1952
|
-
const firstGuid = pack.assets?.[0]?.guid?.toLowerCase();
|
|
1953
|
-
if (pack.schemaVersion !== "2.0.0" || firstGuid === void 0) {
|
|
1954
|
-
return { pack, ...firstGuid === void 0 ? {} : { firstGuid } };
|
|
1955
|
-
}
|
|
1956
|
-
const cooked = await readCookedAuthoredPack(pack, cookers, sourcePath);
|
|
1957
|
-
if (cooked === void 0) return { pack, firstGuid };
|
|
1958
|
-
return {
|
|
1959
|
-
pack,
|
|
1960
|
-
firstGuid,
|
|
1961
|
-
cooked,
|
|
1962
|
-
finalized: await finalizePackageTransportSource(cooked.logicalPackage, policyFor(firstGuid))
|
|
1963
|
-
};
|
|
1964
|
-
}
|
|
1965
2587
|
function projectScriptablePackPublication(product) {
|
|
1966
2588
|
const assets = new Map(product.product.assets.map((asset) => [asset.guid.toLowerCase(), asset]));
|
|
1967
2589
|
const outputs = [];
|
|
1968
2590
|
for (const staged of product.stagedOutputs) {
|
|
1969
|
-
const guid = AssetGuid.format(staged.guid).toLowerCase();
|
|
2591
|
+
const guid = AssetGuid$1.format(staged.guid).toLowerCase();
|
|
1970
2592
|
const asset = assets.get(guid);
|
|
1971
|
-
if (asset === void 0 || staged.digest === void 0) {
|
|
2593
|
+
if (asset === void 0 || staged.digest === void 0 || staged.sourceKey === void 0) {
|
|
1972
2594
|
return err({
|
|
1973
2595
|
code: "pack-source-output-invalid",
|
|
1974
|
-
expected: `ScriptablePack publication output ${guid} to include a product and digest`,
|
|
1975
|
-
hint: "repair the
|
|
2596
|
+
expected: `ScriptablePack publication output ${guid} to include a product, sourceKey, and digest`,
|
|
2597
|
+
hint: "repair the dynamic Pack output and rebuild the current generation",
|
|
1976
2598
|
detail: { stage: "publication", guid }
|
|
1977
2599
|
});
|
|
1978
2600
|
}
|
|
1979
2601
|
outputs.push({
|
|
1980
2602
|
guid,
|
|
1981
|
-
sourceKey: staged.sourceKey
|
|
2603
|
+
sourceKey: staged.sourceKey,
|
|
1982
2604
|
kind: asset.kind,
|
|
1983
2605
|
digest: staged.digest,
|
|
1984
2606
|
refs: asset.refs.map((reference) => reference.guid)
|
|
@@ -1994,130 +2616,115 @@ function projectScriptablePackPublication(product) {
|
|
|
1994
2616
|
)
|
|
1995
2617
|
});
|
|
1996
2618
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
)
|
|
2619
|
+
function snapshotSourceForStagedOutputs(outputs) {
|
|
2620
|
+
if (outputs.length === 0) return void 0;
|
|
2621
|
+
const byGuid = new Map(
|
|
2622
|
+
outputs.map((output) => [AssetGuid$1.format(output.guid).toLowerCase(), output])
|
|
2002
2623
|
);
|
|
2003
|
-
return {
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
const products = /* @__PURE__ */ new Map();
|
|
2016
|
-
const owners = [...entries.entries()].map(
|
|
2017
|
-
([displaySourcePath, entry]) => ({
|
|
2018
|
-
id: displaySourcePath,
|
|
2019
|
-
guids: Object.values(entry.definition.assets).map((asset) => asset.guid),
|
|
2020
|
-
async build(source) {
|
|
2021
|
-
const produced = await produceScriptableSourcePackage({
|
|
2022
|
-
definition: entry.definition,
|
|
2023
|
-
sourcePath: displaySourcePath,
|
|
2024
|
-
assetSource: source,
|
|
2025
|
-
outputs: createStandardAssetOutputProducerRegistry(
|
|
2026
|
-
projectScriptablePackSceneComponents(entry.definition.sceneComponents)
|
|
2027
|
-
),
|
|
2028
|
-
sourceClosure: entry.closure,
|
|
2029
|
-
authoringContractVersion: "scriptable-pack-production/1"
|
|
2030
|
-
});
|
|
2031
|
-
if (!produced.ok) return produced;
|
|
2032
|
-
const observedClosure = await inventoryScriptablePackSource(entry.source.sourcePath);
|
|
2033
|
-
if (JSON.stringify(observedClosure) !== JSON.stringify(entry.closure)) {
|
|
2034
|
-
return err({
|
|
2035
|
-
code: "pack-source-load-failed",
|
|
2036
|
-
expected: "the complete ScriptablePack module closure to remain fixed during one build",
|
|
2037
|
-
hint: "retry the build after source and helper writes have settled",
|
|
2038
|
-
detail: {
|
|
2039
|
-
sourcePath: displaySourcePath,
|
|
2040
|
-
reason: "source-changed",
|
|
2041
|
-
phase: "build",
|
|
2042
|
-
diagnostic: "module closure changed while the staged generation was building"
|
|
2043
|
-
}
|
|
2044
|
-
});
|
|
2045
|
-
}
|
|
2046
|
-
products.set(displaySourcePath, produced.value);
|
|
2047
|
-
return ok(produced.value.stagedOutputs);
|
|
2624
|
+
return {
|
|
2625
|
+
async readByGuid(guid) {
|
|
2626
|
+
const key = AssetGuid$1.format(guid).toLowerCase();
|
|
2627
|
+
const output = byGuid.get(key);
|
|
2628
|
+
if (output === void 0) {
|
|
2629
|
+
return err(
|
|
2630
|
+
new AssetError({
|
|
2631
|
+
code: "asset-not-found",
|
|
2632
|
+
expected: `an available Asset snapshot for ${key}`,
|
|
2633
|
+
hint: "publish the referenced Pack or repair the content dependency"
|
|
2634
|
+
})
|
|
2635
|
+
);
|
|
2048
2636
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
[...entries.values()].flatMap((entry) => entry.closure).sort((a, b) => a.path.localeCompare(b.path))
|
|
2054
|
-
)
|
|
2055
|
-
).digest();
|
|
2056
|
-
const stagedSource = createScriptablePackStagedAssetSnapshotSource({
|
|
2057
|
-
generation: generationDigest.readUInt32BE(0),
|
|
2058
|
-
owners,
|
|
2059
|
-
declaredExternalOutputs
|
|
2060
|
-
});
|
|
2061
|
-
const prepared = /* @__PURE__ */ new Map();
|
|
2062
|
-
for (const source of sources) {
|
|
2063
|
-
const entry = entries.get(source.displaySourcePath);
|
|
2064
|
-
if (entry === void 0) {
|
|
2065
|
-
return err({
|
|
2066
|
-
code: "pack-source-path-invalid",
|
|
2067
|
-
expected: "a ScriptablePack source registered in the current inventory",
|
|
2068
|
-
actual: source.displaySourcePath,
|
|
2069
|
-
hint: "rebuild the source inventory before producing this path",
|
|
2070
|
-
retryable: true,
|
|
2071
|
-
recoveryActions: ["rebuild-source-inventory"],
|
|
2072
|
-
detail: { sourcePath: source.displaySourcePath }
|
|
2637
|
+
return ok({
|
|
2638
|
+
asset: structuredClone(output.asset),
|
|
2639
|
+
generation: 1,
|
|
2640
|
+
digest: output.digest ?? "sha256:staged"
|
|
2073
2641
|
});
|
|
2074
2642
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
function composeScriptablePackAssetSource(staged, published) {
|
|
2646
|
+
if (staged === void 0) return published;
|
|
2647
|
+
if (published === void 0) return staged;
|
|
2648
|
+
return {
|
|
2649
|
+
async readByGuid(guid) {
|
|
2650
|
+
const local = await staged.readByGuid(guid);
|
|
2651
|
+
if (local.ok || local.error.code !== "asset-not-found") return local;
|
|
2652
|
+
return published.readByGuid(guid);
|
|
2083
2653
|
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
async function produceScriptablePackProducts(options) {
|
|
2657
|
+
if (options.sources.length === 0) return ok(/* @__PURE__ */ new Map());
|
|
2658
|
+
const external = options.declaredExternalOutputs ?? [];
|
|
2659
|
+
const assetSource = composeScriptablePackAssetSource(
|
|
2660
|
+
snapshotSourceForStagedOutputs(external),
|
|
2661
|
+
options.assetSource
|
|
2662
|
+
);
|
|
2663
|
+
const availableGuids = /* @__PURE__ */ new Set([
|
|
2664
|
+
...options.availableGuids ?? [],
|
|
2665
|
+
...external.map((output) => AssetGuid$1.format(output.guid).toLowerCase())
|
|
2666
|
+
]);
|
|
2667
|
+
const workItems = options.sources.map((source) => ({
|
|
2668
|
+
definition: source.definition,
|
|
2669
|
+
sourcePath: source.sourcePath,
|
|
2670
|
+
...source.subjectPackageId === void 0 ? {} : { subjectPackageId: source.subjectPackageId },
|
|
2671
|
+
...source.values === void 0 ? {} : { values: source.values },
|
|
2672
|
+
...source.inheritedValues === void 0 ? {} : { inheritedValues: source.inheritedValues },
|
|
2673
|
+
sourceClosure: source.sourceClosure
|
|
2674
|
+
}));
|
|
2675
|
+
const worklist = await buildScriptablePackWorklist({
|
|
2676
|
+
subjects: workItems,
|
|
2677
|
+
outputs: createStandardAssetOutputProducerRegistry(
|
|
2678
|
+
options.sources.flatMap(
|
|
2679
|
+
(source) => projectScriptablePackSceneComponents(source.definition.sceneComponents)
|
|
2680
|
+
)
|
|
2681
|
+
),
|
|
2682
|
+
...assetSource === void 0 ? {} : { assetSource },
|
|
2683
|
+
availableGuids,
|
|
2684
|
+
...options.incomingRefs === void 0 ? {} : { incomingRefs: options.incomingRefs },
|
|
2685
|
+
...options.maxPasses === void 0 ? {} : { maxPasses: options.maxPasses }
|
|
2686
|
+
});
|
|
2687
|
+
if (!worklist.ok) return worklist;
|
|
2688
|
+
const productsBySource = new Map(
|
|
2689
|
+
worklist.value.buildProducts.filter((product) => product.product.sourceKey !== void 0).map((product) => [product.product.sourceKey, product])
|
|
2690
|
+
);
|
|
2691
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
2692
|
+
for (const source of options.sources) {
|
|
2693
|
+
const product = productsBySource.get(source.sourcePath);
|
|
2694
|
+
if (product === void 0) {
|
|
2088
2695
|
return err({
|
|
2089
2696
|
code: "pack-source-output-invalid",
|
|
2090
|
-
expected: "
|
|
2091
|
-
hint: "
|
|
2092
|
-
detail: {
|
|
2093
|
-
missingGuids: [AssetGuid.format(first.guid)],
|
|
2094
|
-
unexpectedSourceKeys: [],
|
|
2095
|
-
kindMismatches: []
|
|
2096
|
-
}
|
|
2697
|
+
expected: "one terminal dynamic Pack product for every source subject",
|
|
2698
|
+
hint: "rerun the bounded generation worklist and inspect its subject map",
|
|
2699
|
+
detail: { sourcePath: source.sourcePath }
|
|
2097
2700
|
});
|
|
2098
2701
|
}
|
|
2099
|
-
const
|
|
2100
|
-
const
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2702
|
+
const policy = typeof source.policy === "function" ? source.policy(product) : source.policy;
|
|
2703
|
+
const finalized = await finalizePackageTransportSource(
|
|
2704
|
+
projectImportProductForBuild(product.product),
|
|
2705
|
+
policy
|
|
2706
|
+
);
|
|
2707
|
+
const facts = projectScriptablePackPublication(product);
|
|
2708
|
+
if (!facts.ok) return facts;
|
|
2104
2709
|
const revision = await scriptablePackResourceRevision(
|
|
2105
2710
|
source.displaySourcePath,
|
|
2106
|
-
|
|
2711
|
+
product.inputFingerprint,
|
|
2107
2712
|
source.sourceClosure
|
|
2108
2713
|
);
|
|
2109
2714
|
const publication = createAcceptedPublication({
|
|
2110
2715
|
sourcePath: source.displaySourcePath,
|
|
2111
|
-
sourceRevision:
|
|
2716
|
+
sourceRevision: product.inputFingerprint,
|
|
2112
2717
|
generation: source.publicationGeneration,
|
|
2113
2718
|
digest: finalized.digest,
|
|
2114
2719
|
packageUrl: finalized.packageUrl,
|
|
2115
|
-
inputFingerprint:
|
|
2720
|
+
inputFingerprint: product.inputFingerprint,
|
|
2116
2721
|
outputs: facts.value.outputs,
|
|
2117
|
-
externalEvidence:
|
|
2722
|
+
externalEvidence: product.externalEvidence
|
|
2118
2723
|
});
|
|
2119
2724
|
prepared.set(source.displaySourcePath, {
|
|
2120
|
-
product:
|
|
2725
|
+
product: {
|
|
2726
|
+
...product
|
|
2727
|
+
},
|
|
2121
2728
|
finalized,
|
|
2122
2729
|
facts: facts.value,
|
|
2123
2730
|
revision,
|
|
@@ -2126,6 +2733,22 @@ async function produceScriptablePackProducts(sources, declaredExternalOutputs =
|
|
|
2126
2733
|
}
|
|
2127
2734
|
return ok(prepared);
|
|
2128
2735
|
}
|
|
2736
|
+
async function scriptablePackResourceRevision(displaySourcePath, digest3, sourceClosure) {
|
|
2737
|
+
const mtimes = await Promise.all(
|
|
2738
|
+
sourceClosure.map(async (entry) => {
|
|
2739
|
+
try {
|
|
2740
|
+
return (await stat(entry.path)).mtimeMs;
|
|
2741
|
+
} catch (error) {
|
|
2742
|
+
if (error !== null && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
2743
|
+
return 0;
|
|
2744
|
+
}
|
|
2745
|
+
throw error;
|
|
2746
|
+
}
|
|
2747
|
+
})
|
|
2748
|
+
);
|
|
2749
|
+
const observedAt = mtimes.length === 0 ? 0 : Math.trunc(Math.max(...mtimes));
|
|
2750
|
+
return { digest: digest3, observedAt, rootId: displaySourcePath };
|
|
2751
|
+
}
|
|
2129
2752
|
function normalizeCatalogPath(path) {
|
|
2130
2753
|
return path.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
2131
2754
|
}
|
|
@@ -2148,120 +2771,273 @@ function scriptableArtifactPath(guid, key) {
|
|
|
2148
2771
|
return `${guid.toLowerCase()}/${key.includes(".") ? key : `${key}.bin`}`;
|
|
2149
2772
|
}
|
|
2150
2773
|
function runtimePublicationFor(context, input) {
|
|
2151
|
-
|
|
2774
|
+
const publicationInput = {
|
|
2152
2775
|
pack: input.pack,
|
|
2153
2776
|
scopeId: context.runtimeBinding?.scopeId ?? "asset-runtime",
|
|
2154
2777
|
sourcePath: input.sourcePath,
|
|
2155
2778
|
sourceRevision: input.sourceRevision,
|
|
2156
2779
|
packageUrl: input.packageUrl,
|
|
2157
2780
|
...input.digest === void 0 ? {} : { digest: input.digest },
|
|
2781
|
+
...input.inputFingerprint === void 0 ? {} : { inputFingerprint: input.inputFingerprint },
|
|
2782
|
+
...input.outputs === void 0 ? {} : { outputs: input.outputs },
|
|
2783
|
+
...input.externalEvidence === void 0 ? {} : { externalEvidence: input.externalEvidence },
|
|
2158
2784
|
generation: context.runtimeBinding?.generation ?? context.generation
|
|
2785
|
+
};
|
|
2786
|
+
if (input.sourceKeys === void 0) return createRuntimePackPublication(publicationInput);
|
|
2787
|
+
const derived = createRuntimePackPublication(publicationInput);
|
|
2788
|
+
const outputs = derived.publication.outputs.map((output) => ({
|
|
2789
|
+
...output,
|
|
2790
|
+
sourceKey: input.sourceKeys?.get(output.guid.toLowerCase()) ?? output.sourceKey
|
|
2791
|
+
}));
|
|
2792
|
+
return createRuntimePackPublication({ ...publicationInput, outputs });
|
|
2793
|
+
}
|
|
2794
|
+
function sourceKeysFor(declarations) {
|
|
2795
|
+
return new Map(
|
|
2796
|
+
declarations.flatMap(
|
|
2797
|
+
(declaration) => declaration.sourceKey === void 0 ? [] : [[declaration.guid.toLowerCase(), declaration.sourceKey]]
|
|
2798
|
+
)
|
|
2799
|
+
);
|
|
2800
|
+
}
|
|
2801
|
+
function dynamicFailure(context, value) {
|
|
2802
|
+
const candidate = value !== null && typeof value === "object" ? value : {};
|
|
2803
|
+
const error = candidate;
|
|
2804
|
+
throw context.fail({
|
|
2805
|
+
code: typeof error.code === "string" ? error.code : "pack-build-failed",
|
|
2806
|
+
expected: typeof error.expected === "string" ? error.expected : "the Pack source generation to produce a valid terminal result",
|
|
2807
|
+
hint: typeof error.hint === "string" ? error.hint : "inspect the Pack source subject and rebuild the current generation",
|
|
2808
|
+
...error.detail === void 0 ? {} : { detail: error.detail }
|
|
2159
2809
|
});
|
|
2160
2810
|
}
|
|
2161
|
-
|
|
2162
|
-
const
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
(
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2811
|
+
function packCatalogSourcePath(context, sourcePath) {
|
|
2812
|
+
const projected = context.fsForImport.sourceIdentityFor?.(sourcePath);
|
|
2813
|
+
const logical = projected === void 0 || isAbsolute(projected) ? relative(context.cwd, sourcePath) : projected;
|
|
2814
|
+
return canonicalScriptableSourcePath(logical).replaceAll("\\", "/");
|
|
2815
|
+
}
|
|
2816
|
+
async function buildPackSources(context) {
|
|
2817
|
+
const subjects = /* @__PURE__ */ new Map();
|
|
2818
|
+
for (const [sourcePath, declaration] of context.inventory.sourceDeclarations) {
|
|
2819
|
+
if (declaration.format === "pack.ts") {
|
|
2820
|
+
const key = PackageId.format(declaration.definition.packageId).toLowerCase();
|
|
2821
|
+
subjects.set(key, {
|
|
2822
|
+
kind: "source",
|
|
2823
|
+
packageId: declaration.definition.packageId,
|
|
2824
|
+
sourcePath,
|
|
2825
|
+
definition: declaration.definition,
|
|
2826
|
+
sourceClosure: declaration.sourceClosure
|
|
2827
|
+
});
|
|
2828
|
+
continue;
|
|
2829
|
+
}
|
|
2830
|
+
if (declaration.format !== "pack.json" || declaration.value.schemaVersion !== "3.0.0") {
|
|
2831
|
+
continue;
|
|
2832
|
+
}
|
|
2833
|
+
const parsed = parsePackSourceJson(declaration.value);
|
|
2834
|
+
if (!parsed.ok) dynamicFailure(context, parsed.error);
|
|
2835
|
+
if (parsed.value.format === "direct") {
|
|
2836
|
+
subjects.set(PackageId.format(parsed.value.packageId).toLowerCase(), {
|
|
2837
|
+
kind: "direct",
|
|
2838
|
+
packageId: parsed.value.packageId,
|
|
2839
|
+
sourcePath
|
|
2840
|
+
});
|
|
2841
|
+
} else {
|
|
2842
|
+
subjects.set(PackageId.format(parsed.value.packageId).toLowerCase(), {
|
|
2843
|
+
kind: "instance",
|
|
2844
|
+
packageId: parsed.value.packageId,
|
|
2845
|
+
parent: parsed.value.parent,
|
|
2846
|
+
values: parsed.value.values,
|
|
2847
|
+
sourcePath
|
|
2848
|
+
});
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
const sourceSubject = (packageId) => {
|
|
2852
|
+
const subject = subjects.get(PackageId.format(packageId).toLowerCase());
|
|
2853
|
+
return subject?.kind === "source" ? subject : void 0;
|
|
2854
|
+
};
|
|
2855
|
+
const readSubject = async (packageId) => {
|
|
2856
|
+
const subject = subjects.get(PackageId.format(packageId).toLowerCase());
|
|
2857
|
+
if (subject === void 0) return void 0;
|
|
2858
|
+
if (subject.kind === "source") {
|
|
2859
|
+
return {
|
|
2860
|
+
format: "source",
|
|
2861
|
+
packageId: subject.packageId,
|
|
2862
|
+
parameters: "parameters" in subject.definition ? subject.definition.parameters : []
|
|
2863
|
+
};
|
|
2864
|
+
}
|
|
2865
|
+
if (subject.kind === "instance") {
|
|
2866
|
+
return {
|
|
2867
|
+
format: "instance",
|
|
2868
|
+
packageId: subject.packageId,
|
|
2869
|
+
parent: subject.parent,
|
|
2870
|
+
values: subject.values
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2873
|
+
return {
|
|
2874
|
+
format: "direct",
|
|
2875
|
+
packageId: subject.packageId
|
|
2876
|
+
};
|
|
2877
|
+
};
|
|
2878
|
+
const orderedSubjects = [...subjects.values()].sort(
|
|
2879
|
+
(left, right) => left.sourcePath.localeCompare(right.sourcePath)
|
|
2175
2880
|
);
|
|
2176
|
-
const
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
{
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2881
|
+
const inputs = [];
|
|
2882
|
+
for (const subject of orderedSubjects) {
|
|
2883
|
+
if (subject.kind === "source") {
|
|
2884
|
+
const packageId = PackageId.format(subject.packageId);
|
|
2885
|
+
const loaded = await loadScriptablePack(subject.sourcePath);
|
|
2886
|
+
if (!loaded.ok) dynamicFailure(context, loaded.error);
|
|
2887
|
+
if (PackageId.format(loaded.value.packageId) !== packageId) {
|
|
2888
|
+
dynamicFailure(context, {
|
|
2889
|
+
code: "pack-source-revision-conflict",
|
|
2890
|
+
expected: "the ScriptablePack source packageId to remain fixed during production",
|
|
2891
|
+
hint: "retry after source writes settle and rebuild the current generation",
|
|
2892
|
+
detail: {
|
|
2893
|
+
sourcePath: subject.sourcePath,
|
|
2894
|
+
scannedPackageId: packageId,
|
|
2895
|
+
loadedPackageId: PackageId.format(loaded.value.packageId)
|
|
2896
|
+
}
|
|
2897
|
+
});
|
|
2186
2898
|
}
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
hint: "rerun the source inventory and rebuild from the accepted declaration set",
|
|
2199
|
-
detail: { stage: "scan", sourcePath: entry.sourcePath }
|
|
2899
|
+
inputs.push({
|
|
2900
|
+
sourcePath: subject.sourcePath,
|
|
2901
|
+
displaySourcePath: packCatalogSourcePath(context, subject.sourcePath),
|
|
2902
|
+
definition: loaded.value,
|
|
2903
|
+
sourceClosure: subject.sourceClosure,
|
|
2904
|
+
publicationGeneration: context.generation,
|
|
2905
|
+
policy: {
|
|
2906
|
+
base: context.basePrefix === "" ? "/" : context.basePrefix,
|
|
2907
|
+
packagePath: `assets/${packageId}.pack.json`,
|
|
2908
|
+
artifactPath: scriptableArtifactPath
|
|
2909
|
+
}
|
|
2200
2910
|
});
|
|
2201
2911
|
}
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
scopeId: context.runtimeBinding?.scopeId ?? "asset-runtime",
|
|
2207
|
-
sourcePath: publication.sourcePath,
|
|
2208
|
-
sourceRevision: publication.sourceRevision,
|
|
2209
|
-
packageUrl: finalized.packageUrl,
|
|
2210
|
-
inputFingerprint: publication.receipt.inputFingerprint,
|
|
2211
|
-
digest: finalized.digest,
|
|
2212
|
-
generation: context.runtimeBinding?.generation ?? publication.generation,
|
|
2213
|
-
outputs: facts.outputs,
|
|
2214
|
-
externalEvidence: publication.externalEvidence
|
|
2215
|
-
});
|
|
2216
|
-
const receiptPaths = await materializePreparedScriptablePack(
|
|
2217
|
-
prepared,
|
|
2912
|
+
}
|
|
2913
|
+
for (const subject of orderedSubjects) {
|
|
2914
|
+
if (subject.kind !== "instance") continue;
|
|
2915
|
+
const resolved = await resolvePackParameterInheritance(
|
|
2218
2916
|
{
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2917
|
+
format: "instance",
|
|
2918
|
+
packageId: subject.packageId,
|
|
2919
|
+
parent: subject.parent,
|
|
2920
|
+
values: subject.values
|
|
2222
2921
|
},
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2922
|
+
readSubject
|
|
2923
|
+
);
|
|
2924
|
+
if (!resolved.ok) dynamicFailure(context, resolved.error);
|
|
2925
|
+
const root = sourceSubject(resolved.value.rootPackageId);
|
|
2926
|
+
if (root === void 0) {
|
|
2927
|
+
dynamicFailure(context, {
|
|
2928
|
+
code: "pack-parent-has-no-parameters",
|
|
2929
|
+
expected: "the instance parent chain to terminate at a ScriptablePack source",
|
|
2930
|
+
hint: "point the instance at a ScriptablePack *.pack.ts source with parameters",
|
|
2931
|
+
detail: { packageId: PackageId.format(subject.packageId) }
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
const loaded = await loadScriptablePack(root.sourcePath);
|
|
2935
|
+
if (!loaded.ok) dynamicFailure(context, loaded.error);
|
|
2936
|
+
if (PackageId.format(loaded.value.packageId) !== PackageId.format(root.packageId)) {
|
|
2937
|
+
dynamicFailure(context, {
|
|
2938
|
+
code: "pack-source-revision-conflict",
|
|
2939
|
+
expected: "the ScriptablePack parent packageId to remain fixed during production",
|
|
2940
|
+
hint: "retry after source writes settle and rebuild the current generation",
|
|
2941
|
+
detail: {
|
|
2942
|
+
sourcePath: root.sourcePath,
|
|
2943
|
+
scannedPackageId: PackageId.format(root.packageId),
|
|
2944
|
+
loadedPackageId: PackageId.format(loaded.value.packageId)
|
|
2237
2945
|
}
|
|
2946
|
+
});
|
|
2947
|
+
}
|
|
2948
|
+
const packageId = PackageId.format(subject.packageId);
|
|
2949
|
+
inputs.push({
|
|
2950
|
+
sourcePath: subject.sourcePath,
|
|
2951
|
+
displaySourcePath: packCatalogSourcePath(context, subject.sourcePath),
|
|
2952
|
+
definition: loaded.value,
|
|
2953
|
+
sourceClosure: root.sourceClosure,
|
|
2954
|
+
subjectPackageId: subject.packageId,
|
|
2955
|
+
values: resolved.value.values,
|
|
2956
|
+
publicationGeneration: context.generation,
|
|
2957
|
+
policy: {
|
|
2958
|
+
base: context.basePrefix === "" ? "/" : context.basePrefix,
|
|
2959
|
+
packagePath: `assets/${packageId}.pack.json`,
|
|
2960
|
+
artifactPath: scriptableArtifactPath
|
|
2238
2961
|
}
|
|
2239
|
-
);
|
|
2240
|
-
result.set(entry.sourcePath, {
|
|
2241
|
-
packageUrl: finalized.packageUrl,
|
|
2242
|
-
receiptUrls: new Map(
|
|
2243
|
-
[...receiptPaths].map(([guid, path]) => [guid, context.sink.fileUrl(path)])
|
|
2244
|
-
),
|
|
2245
|
-
revision,
|
|
2246
|
-
publication: runtimePublication.publication,
|
|
2247
|
-
refs: facts.refs
|
|
2248
2962
|
});
|
|
2249
2963
|
}
|
|
2250
|
-
return
|
|
2964
|
+
if (inputs.length === 0) return [];
|
|
2965
|
+
const requiredGuids = context.inventory.entries.flatMap((entry) => {
|
|
2966
|
+
const parsed = AssetGuid$1.parse(entry.guid);
|
|
2967
|
+
if (!parsed.ok) dynamicFailure(context, parsed.error);
|
|
2968
|
+
return [parsed.value];
|
|
2969
|
+
});
|
|
2970
|
+
const externalOutputs = await declaredPackExternalOutputs(
|
|
2971
|
+
context.inventory.sourceDeclarations,
|
|
2972
|
+
context.cookers,
|
|
2973
|
+
requiredGuids,
|
|
2974
|
+
{
|
|
2975
|
+
importerRegistry: context.importerRegistry,
|
|
2976
|
+
fsForImport: context.fsForImport
|
|
2977
|
+
}
|
|
2978
|
+
);
|
|
2979
|
+
const availableGuids = new Set(requiredGuids.map((guid) => AssetGuid$1.format(guid).toLowerCase()));
|
|
2980
|
+
const built = await produceScriptablePackProducts({
|
|
2981
|
+
sources: inputs,
|
|
2982
|
+
declaredExternalOutputs: externalOutputs,
|
|
2983
|
+
availableGuids
|
|
2984
|
+
});
|
|
2985
|
+
if (!built.ok) dynamicFailure(context, built.error);
|
|
2986
|
+
const bundles = [];
|
|
2987
|
+
for (const input of inputs) {
|
|
2988
|
+
const prepared = built.value.get(input.displaySourcePath);
|
|
2989
|
+
if (prepared === void 0) {
|
|
2990
|
+
dynamicFailure(context, {
|
|
2991
|
+
code: "pack-build-failed",
|
|
2992
|
+
expected: "the worklist to return one prepared result per source subject",
|
|
2993
|
+
hint: "rerun Pack source generation from a clean inventory",
|
|
2994
|
+
detail: { sourcePath: input.sourcePath }
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
const packageId = PackageId.format(input.subjectPackageId ?? input.definition.packageId);
|
|
2998
|
+
const stagedByGuid = new Map(
|
|
2999
|
+
prepared.product.stagedOutputs.map((output) => [
|
|
3000
|
+
AssetGuid$1.format(output.guid).toLowerCase(),
|
|
3001
|
+
output
|
|
3002
|
+
])
|
|
3003
|
+
);
|
|
3004
|
+
const entries = projectPackageCatalog(
|
|
3005
|
+
prepared.product.product.assets.map((asset, sourceIndex) => {
|
|
3006
|
+
const staged = stagedByGuid.get(asset.guid.toLowerCase());
|
|
3007
|
+
return {
|
|
3008
|
+
guid: asset.guid,
|
|
3009
|
+
kind: asset.kind,
|
|
3010
|
+
sourcePath: input.displaySourcePath,
|
|
3011
|
+
sourceIndex,
|
|
3012
|
+
...staged?.sourceKey === void 0 ? {} : { sourceKey: staged.sourceKey },
|
|
3013
|
+
refs: asset.refs.map((reference) => reference.guid),
|
|
3014
|
+
execution: "cooked",
|
|
3015
|
+
packageId,
|
|
3016
|
+
provenance: { provider: "pack-ts", version: "2.0.0" }
|
|
3017
|
+
};
|
|
3018
|
+
}),
|
|
3019
|
+
`${context.basePrefix === "/" ? "" : context.basePrefix}/${input.displaySourcePath}`
|
|
3020
|
+
);
|
|
3021
|
+
bundles.push({ input, prepared, entries });
|
|
3022
|
+
}
|
|
3023
|
+
return bundles;
|
|
2251
3024
|
}
|
|
2252
|
-
function updateImportedEntries(entries, guids, packageUrl, projection = {}, refsByGuid, publication, sourcePath) {
|
|
3025
|
+
function updateImportedEntries(entries, guids, packageUrl, projection = {}, refsByGuid, publication, sourcePath, receiptUrls, revision) {
|
|
2253
3026
|
const selected = new Set(guids.map((guid) => guid.toLowerCase()));
|
|
2254
3027
|
for (let index = 0; index < entries.length; index += 1) {
|
|
2255
3028
|
const entry = entries[index];
|
|
2256
3029
|
if (entry === void 0 || !selected.has(entry.guid.toLowerCase())) continue;
|
|
2257
3030
|
const refs = refsByGuid?.get(entry.guid.toLowerCase());
|
|
3031
|
+
const cookReceiptUrl = receiptUrls?.get(entry.guid.toLowerCase());
|
|
2258
3032
|
entries[index] = {
|
|
2259
3033
|
...entry,
|
|
2260
3034
|
packageUrl,
|
|
2261
3035
|
...projection,
|
|
2262
3036
|
...sourcePath === void 0 ? {} : { sourcePath },
|
|
2263
3037
|
...publication === void 0 ? {} : { publication },
|
|
2264
|
-
...refs === void 0 ? {} : { refs }
|
|
3038
|
+
...refs === void 0 ? {} : { refs },
|
|
3039
|
+
...cookReceiptUrl === void 0 ? {} : { cookReceiptUrl },
|
|
3040
|
+
...revision === void 0 ? {} : { revision }
|
|
2265
3041
|
};
|
|
2266
3042
|
}
|
|
2267
3043
|
}
|
|
@@ -2275,11 +3051,30 @@ async function emitPackDocument(work, options) {
|
|
|
2275
3051
|
}
|
|
2276
3052
|
const referenceId = work.context.sink.emitFile({
|
|
2277
3053
|
type: "asset",
|
|
3054
|
+
fileName: options.packageName.startsWith("assets/") ? options.packageName : `assets/${options.packageName}`,
|
|
2278
3055
|
name: options.packageName,
|
|
2279
3056
|
originalFileName: options.originalFileName,
|
|
2280
3057
|
source: JSON.stringify(options.pack)
|
|
2281
3058
|
});
|
|
2282
3059
|
const packageUrl = work.context.sink.fileUrl(work.context.sink.getFileName(referenceId));
|
|
3060
|
+
const receiptUrls = /* @__PURE__ */ new Map();
|
|
3061
|
+
for (const receipt of options.receipts ?? []) {
|
|
3062
|
+
const guid = receipt.guid.toLowerCase();
|
|
3063
|
+
const receiptReferenceId = work.context.sink.emitFile({
|
|
3064
|
+
type: "asset",
|
|
3065
|
+
fileName: `assets/${guid}.receipt.json`,
|
|
3066
|
+
name: `${guid}.receipt.json`,
|
|
3067
|
+
originalFileName: options.originalFileName,
|
|
3068
|
+
source: JSON.stringify({
|
|
3069
|
+
...receipt,
|
|
3070
|
+
...receipt.outputDigest === void 0 && options.receiptOutputDigest === void 0 ? {} : { outputDigest: receipt.outputDigest ?? options.receiptOutputDigest }
|
|
3071
|
+
})
|
|
3072
|
+
});
|
|
3073
|
+
receiptUrls.set(
|
|
3074
|
+
guid,
|
|
3075
|
+
work.context.sink.fileUrl(work.context.sink.getFileName(receiptReferenceId))
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
2283
3078
|
updateImportedEntries(
|
|
2284
3079
|
work.importedEntries,
|
|
2285
3080
|
options.guids,
|
|
@@ -2287,11 +3082,13 @@ async function emitPackDocument(work, options) {
|
|
|
2287
3082
|
options.projection,
|
|
2288
3083
|
options.refsByGuid,
|
|
2289
3084
|
options.publication,
|
|
2290
|
-
options.sourcePath
|
|
3085
|
+
options.sourcePath,
|
|
3086
|
+
receiptUrls,
|
|
3087
|
+
options.revision
|
|
2291
3088
|
);
|
|
2292
3089
|
return packageUrl;
|
|
2293
3090
|
}
|
|
2294
|
-
async function emitAuthoredPack(work, guidSeen, entry) {
|
|
3091
|
+
async function emitAuthoredPack(work, guidSeen, entry, availableGuids) {
|
|
2295
3092
|
const sourceDeclaration = sourceDeclarationForCatalogPath(
|
|
2296
3093
|
entry.sourcePath,
|
|
2297
3094
|
work.context.inventory.sourceDeclarations,
|
|
@@ -2308,39 +3105,143 @@ async function emitAuthoredPack(work, guidSeen, entry) {
|
|
|
2308
3105
|
detail: { stage: "scan", sourcePath: packPath }
|
|
2309
3106
|
});
|
|
2310
3107
|
}
|
|
2311
|
-
|
|
2312
|
-
declaration.value
|
|
3108
|
+
if (declaration.value.schemaVersion === "3.0.0") {
|
|
3109
|
+
const parsed = parsePackSourceJson(declaration.value);
|
|
3110
|
+
if (!parsed.ok) dynamicFailure(work.context, parsed.error);
|
|
3111
|
+
if (parsed.value.format !== "direct") {
|
|
3112
|
+
dynamicFailure(work.context, {
|
|
3113
|
+
code: "catalog-declaration-missing",
|
|
3114
|
+
expected: "a direct v3 Pack declaration for an indexed authored output",
|
|
3115
|
+
hint: "instances are built from their ScriptablePack parent and do not have direct Catalog rows",
|
|
3116
|
+
detail: { stage: "scan", sourcePath: packPath }
|
|
3117
|
+
});
|
|
3118
|
+
}
|
|
3119
|
+
const projected = projectDirectPackJson(parsed.value);
|
|
3120
|
+
if (!projected.ok) dynamicFailure(work.context, projected.error);
|
|
3121
|
+
const prepared2 = await prepareDirectPackTransport({
|
|
3122
|
+
projected: projected.value,
|
|
3123
|
+
sourcePath: packPath,
|
|
3124
|
+
sourceRevision: declaration.sourceRevision,
|
|
3125
|
+
availableGuids,
|
|
3126
|
+
cookers: work.context.cookers,
|
|
3127
|
+
policy: {
|
|
3128
|
+
base: work.context.basePrefix === "" ? "/" : work.context.basePrefix,
|
|
3129
|
+
packagePath: `assets/${projected.value.packageId}.pack.json`,
|
|
3130
|
+
artifactPath: (assetGuid, key) => `${assetGuid}/${key}.bin`,
|
|
3131
|
+
sink: () => {
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
});
|
|
3135
|
+
if (!prepared2.ok) dynamicFailure(work.context, prepared2.error);
|
|
3136
|
+
const { product, finalized, facts, revision } = prepared2.value;
|
|
3137
|
+
const publication = runtimePublicationFor(work.context, {
|
|
3138
|
+
pack: finalized.pack,
|
|
3139
|
+
sourcePath: entry.sourcePath,
|
|
3140
|
+
sourceRevision: product.inputFingerprint,
|
|
3141
|
+
packageUrl: finalized.packageUrl,
|
|
3142
|
+
digest: finalized.digest,
|
|
3143
|
+
inputFingerprint: product.inputFingerprint,
|
|
3144
|
+
outputs: facts.outputs,
|
|
3145
|
+
externalEvidence: product.externalEvidence
|
|
3146
|
+
});
|
|
3147
|
+
await emitPackDocument(work, {
|
|
3148
|
+
pack: publication.pack,
|
|
3149
|
+
artifacts: finalized.artifacts,
|
|
3150
|
+
packageName: `${prepared2.value.projected.packageId}.pack.json`,
|
|
3151
|
+
originalFileName: packPath,
|
|
3152
|
+
guids: product.product.assets.map((asset) => asset.guid),
|
|
3153
|
+
projection: work.context.authoredCookedCurrentProjection,
|
|
3154
|
+
refsByGuid: facts.refs,
|
|
3155
|
+
receipts: product.product.receipts,
|
|
3156
|
+
receiptOutputDigest: finalized.digest,
|
|
3157
|
+
publication: publication.publication,
|
|
3158
|
+
sourcePath: entry.sourcePath,
|
|
3159
|
+
revision
|
|
3160
|
+
});
|
|
3161
|
+
for (const asset of product.product.assets) guidSeen.add(asset.guid.toLowerCase());
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
const legacy = declaration.value;
|
|
3165
|
+
const prepared = await prepareLegacyPackTransport(
|
|
3166
|
+
legacy,
|
|
2313
3167
|
work.context.cookers,
|
|
2314
3168
|
(guid) => ({
|
|
2315
3169
|
base: work.context.basePrefix === "" ? "/" : work.context.basePrefix,
|
|
2316
3170
|
packagePath: `assets/${guid}.pack.json`,
|
|
2317
|
-
artifactPath: (
|
|
3171
|
+
artifactPath: (assetGuid, key) => `${assetGuid}/${key}.bin`
|
|
2318
3172
|
}),
|
|
2319
3173
|
packPath
|
|
2320
3174
|
);
|
|
2321
3175
|
const outputGuid = prepared.firstGuid ?? entry.guid;
|
|
2322
|
-
const authoredPack = prepared.finalized?.pack ??
|
|
2323
|
-
|
|
2324
|
-
|
|
3176
|
+
const authoredPack = prepared.finalized?.pack ?? {
|
|
3177
|
+
schemaVersion: "2.0.0",
|
|
3178
|
+
kind: "internal-text-package",
|
|
3179
|
+
assets: legacy.assets.map((asset) => ({
|
|
3180
|
+
guid: asset.guid,
|
|
3181
|
+
kind: asset.kind,
|
|
3182
|
+
...asset.name === void 0 ? {} : { name: asset.name },
|
|
3183
|
+
payload: asset.payload,
|
|
3184
|
+
refs: asset.refs,
|
|
3185
|
+
artifacts: asset.artifacts ?? {}
|
|
3186
|
+
}))
|
|
3187
|
+
};
|
|
3188
|
+
const runtimePublication = runtimePublicationFor(work.context, {
|
|
3189
|
+
pack: authoredPack,
|
|
2325
3190
|
sourcePath: entry.sourcePath,
|
|
2326
3191
|
sourceRevision: declaration.sourceRevision,
|
|
2327
3192
|
packageUrl: prepared.finalized?.packageUrl ?? `${work.context.basePrefix === "/" ? "" : work.context.basePrefix}/assets/${outputGuid}.pack.json`,
|
|
2328
3193
|
...prepared.finalized?.digest === void 0 ? {} : { digest: prepared.finalized.digest }
|
|
2329
3194
|
});
|
|
2330
3195
|
await emitPackDocument(work, {
|
|
2331
|
-
pack: runtimePublication
|
|
3196
|
+
pack: runtimePublication.pack,
|
|
2332
3197
|
artifacts: prepared.finalized?.artifacts ?? [],
|
|
2333
3198
|
packageName: `${outputGuid}.pack.json`,
|
|
2334
3199
|
originalFileName: packPath,
|
|
2335
|
-
guids:
|
|
3200
|
+
guids: authoredPack.assets.map((asset) => asset.guid),
|
|
2336
3201
|
projection: prepared.finalized === void 0 ? work.context.directCurrentProjection : work.context.authoredCookedCurrentProjection,
|
|
2337
|
-
|
|
2338
|
-
...
|
|
3202
|
+
refsByGuid: new Map(authoredPack.assets.map((asset) => [asset.guid.toLowerCase(), asset.refs])),
|
|
3203
|
+
...prepared.finalized?.receipts === void 0 ? {} : {
|
|
3204
|
+
receipts: prepared.finalized.receipts,
|
|
3205
|
+
receiptOutputDigest: prepared.finalized.digest
|
|
3206
|
+
},
|
|
3207
|
+
publication: runtimePublication.publication,
|
|
3208
|
+
sourcePath: entry.sourcePath
|
|
2339
3209
|
});
|
|
2340
|
-
for (const guid of
|
|
3210
|
+
for (const guid of authoredPack.assets.map((asset) => asset.guid)) {
|
|
2341
3211
|
guidSeen.add(guid.toLowerCase());
|
|
2342
3212
|
}
|
|
2343
3213
|
}
|
|
3214
|
+
async function emitScriptablePack(work, guidSeen, bundle) {
|
|
3215
|
+
const { input, prepared } = bundle;
|
|
3216
|
+
const packageId = PackageId.format(input.subjectPackageId ?? input.definition.packageId);
|
|
3217
|
+
const runtimePublication = createRuntimePackPublication({
|
|
3218
|
+
pack: { assets: prepared.finalized.pack.assets },
|
|
3219
|
+
scopeId: work.context.runtimeBinding?.scopeId ?? "asset-runtime",
|
|
3220
|
+
sourcePath: input.displaySourcePath,
|
|
3221
|
+
sourceRevision: prepared.product.inputFingerprint,
|
|
3222
|
+
packageUrl: prepared.finalized.packageUrl,
|
|
3223
|
+
inputFingerprint: prepared.product.inputFingerprint,
|
|
3224
|
+
digest: prepared.finalized.digest,
|
|
3225
|
+
generation: work.context.runtimeBinding?.generation ?? prepared.publication.generation,
|
|
3226
|
+
outputs: prepared.facts.outputs,
|
|
3227
|
+
externalEvidence: prepared.product.externalEvidence
|
|
3228
|
+
});
|
|
3229
|
+
await emitPackDocument(work, {
|
|
3230
|
+
pack: runtimePublication.pack,
|
|
3231
|
+
artifacts: prepared.finalized.artifacts,
|
|
3232
|
+
packageName: `${packageId}.pack.json`,
|
|
3233
|
+
originalFileName: input.sourcePath,
|
|
3234
|
+
guids: prepared.product.product.assets.map((asset) => asset.guid),
|
|
3235
|
+
projection: work.context.authoredCookedCurrentProjection,
|
|
3236
|
+
refsByGuid: prepared.facts.refs,
|
|
3237
|
+
receipts: prepared.product.product.receipts,
|
|
3238
|
+
receiptOutputDigest: prepared.finalized.digest,
|
|
3239
|
+
publication: runtimePublication.publication,
|
|
3240
|
+
sourcePath: input.displaySourcePath,
|
|
3241
|
+
revision: prepared.revision
|
|
3242
|
+
});
|
|
3243
|
+
for (const asset of prepared.product.product.assets) guidSeen.add(asset.guid.toLowerCase());
|
|
3244
|
+
}
|
|
2344
3245
|
async function emitFinalizedOwner(work, metaPath, sourcePath, subAssets, sourcePackage, ownerFinalizer) {
|
|
2345
3246
|
const ownerGuid = subAssets[0]?.guid;
|
|
2346
3247
|
if (ownerGuid === void 0) return;
|
|
@@ -2409,11 +3310,12 @@ async function emitFinalizedOwner(work, metaPath, sourcePath, subAssets, sourceP
|
|
|
2409
3310
|
sourcePath
|
|
2410
3311
|
});
|
|
2411
3312
|
}
|
|
2412
|
-
async function emitBuildEntry(work, guidSeen, entry) {
|
|
3313
|
+
async function emitBuildEntry(work, guidSeen, entry, availableGuids) {
|
|
2413
3314
|
const guid = entry.guid.toLowerCase();
|
|
2414
3315
|
const metaPath = metaPathForGuid(work.context.inventory.declarations, guid);
|
|
2415
3316
|
if (metaPath === void 0) {
|
|
2416
|
-
if (entry.sourcePath.endsWith(".pack.json"))
|
|
3317
|
+
if (entry.sourcePath.endsWith(".pack.json"))
|
|
3318
|
+
await emitAuthoredPack(work, guidSeen, entry, availableGuids);
|
|
2417
3319
|
else guidSeen.add(guid);
|
|
2418
3320
|
return;
|
|
2419
3321
|
}
|
|
@@ -2466,7 +3368,8 @@ async function emitBuildEntry(work, guidSeen, entry) {
|
|
|
2466
3368
|
sourcePath: canonicalSourcePath,
|
|
2467
3369
|
sourceRevision: finalized.sourceRevision,
|
|
2468
3370
|
packageUrl: finalized.packageUrl,
|
|
2469
|
-
digest: finalized.digest
|
|
3371
|
+
digest: finalized.digest,
|
|
3372
|
+
sourceKeys: sourceKeysFor(subAssets)
|
|
2470
3373
|
});
|
|
2471
3374
|
await emitPackDocument(work, {
|
|
2472
3375
|
pack: runtimePublication.pack,
|
|
@@ -2483,24 +3386,21 @@ async function emitBuildEntry(work, guidSeen, entry) {
|
|
|
2483
3386
|
});
|
|
2484
3387
|
}
|
|
2485
3388
|
async function produceBuildAssets(context) {
|
|
2486
|
-
const
|
|
2487
|
-
const
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
packageUrl: scriptable.packageUrl,
|
|
2494
|
-
revision: scriptable.revision,
|
|
2495
|
-
refs: scriptable.refs.get(entry.guid.toLowerCase()) ?? [],
|
|
2496
|
-
...cookReceiptUrl === void 0 ? {} : { cookReceiptUrl },
|
|
2497
|
-
publication: scriptable.publication
|
|
2498
|
-
});
|
|
2499
|
-
});
|
|
3389
|
+
const dynamicBundles = await buildPackSources(context);
|
|
3390
|
+
const entries = [
|
|
3391
|
+
...context.inventory.entries,
|
|
3392
|
+
...dynamicBundles.flatMap((bundle) => bundle.entries)
|
|
3393
|
+
];
|
|
3394
|
+
const availableGuids = new Set(entries.map((entry) => entry.guid.toLowerCase()));
|
|
3395
|
+
const importedEntries = [...entries];
|
|
2500
3396
|
const guidSeen = /* @__PURE__ */ new Set();
|
|
2501
3397
|
const work = { importedEntries, context };
|
|
3398
|
+
for (const bundle of dynamicBundles) {
|
|
3399
|
+
await emitScriptablePack(work, guidSeen, bundle);
|
|
3400
|
+
}
|
|
2502
3401
|
for (const entry of importedEntries) {
|
|
2503
|
-
if (!guidSeen.has(entry.guid.toLowerCase()))
|
|
3402
|
+
if (!guidSeen.has(entry.guid.toLowerCase()))
|
|
3403
|
+
await emitBuildEntry(work, guidSeen, entry, availableGuids);
|
|
2504
3404
|
}
|
|
2505
3405
|
return importedEntries;
|
|
2506
3406
|
}
|
|
@@ -2531,89 +3431,674 @@ function catalogImporterPolicy(importer, hostImporterKeys) {
|
|
|
2531
3431
|
hint: "let the provider producer materialize the declared output"
|
|
2532
3432
|
};
|
|
2533
3433
|
}
|
|
2534
|
-
if (hostImporterKeys.has(importer)) {
|
|
2535
|
-
return {
|
|
2536
|
-
disposition: "publish",
|
|
2537
|
-
hostProvided: true,
|
|
2538
|
-
expected: "a registered host Catalog provider declaration",
|
|
2539
|
-
hint: "let the registered provider materialize the declared output"
|
|
2540
|
-
};
|
|
3434
|
+
if (hostImporterKeys.has(importer)) {
|
|
3435
|
+
return {
|
|
3436
|
+
disposition: "publish",
|
|
3437
|
+
hostProvided: true,
|
|
3438
|
+
expected: "a registered host Catalog provider declaration",
|
|
3439
|
+
hint: "let the registered provider materialize the declared output"
|
|
3440
|
+
};
|
|
3441
|
+
}
|
|
3442
|
+
return {
|
|
3443
|
+
disposition: "missing",
|
|
3444
|
+
hostProvided: false,
|
|
3445
|
+
expected: "the sidecar importer must be present in the registered provider set",
|
|
3446
|
+
hint: "wire the provider through the host importer registry before building the Catalog"
|
|
3447
|
+
};
|
|
3448
|
+
}
|
|
3449
|
+
async function buildCatalogResult(roots, base = "/", registeredImporterKeys = /* @__PURE__ */ new Set(), scanOptions = {}, catalogVisibility = () => true, sourceIdentityFor) {
|
|
3450
|
+
const options = {
|
|
3451
|
+
base,
|
|
3452
|
+
scanOptions,
|
|
3453
|
+
importerPolicy: (importer) => catalogImporterPolicy(importer, registeredImporterKeys),
|
|
3454
|
+
visibility: catalogVisibility,
|
|
3455
|
+
...sourceIdentityFor === void 0 ? {} : { sourceIdentityFor }
|
|
3456
|
+
};
|
|
3457
|
+
return buildCatalogProjection(roots, options);
|
|
3458
|
+
}
|
|
3459
|
+
function numericTokens(source, startLine) {
|
|
3460
|
+
return source.split(/\r?\n/).slice(startLine).join(" ").replaceAll(",", " ").split(/\s+/).filter((token) => token.length > 0).map(Number);
|
|
3461
|
+
}
|
|
3462
|
+
function allFinite(values) {
|
|
3463
|
+
return values.every(Number.isFinite);
|
|
3464
|
+
}
|
|
3465
|
+
function parseLm63TypeC(source) {
|
|
3466
|
+
const lines = source.split(/\r?\n/);
|
|
3467
|
+
const tiltLine = lines.findIndex((line) => /^\s*TILT\s*=/i.test(line));
|
|
3468
|
+
if (tiltLine < 0) return err({ code: "invalid-ies", reason: "missing TILT declaration" });
|
|
3469
|
+
const tiltSource = lines[tiltLine];
|
|
3470
|
+
if (tiltSource === void 0)
|
|
3471
|
+
return err({ code: "invalid-ies", reason: "missing TILT declaration" });
|
|
3472
|
+
const tilt = tiltSource.slice(tiltSource.indexOf("=") + 1).trim().toUpperCase();
|
|
3473
|
+
if (tilt !== "NONE") return err({ code: "unsupported-tilt", reason: `TILT=${tilt}` });
|
|
3474
|
+
const values = numericTokens(source, tiltLine + 1);
|
|
3475
|
+
if (values.length < 12 || !allFinite(values.slice(0, 12))) {
|
|
3476
|
+
return err({ code: "invalid-ies", reason: "numeric header is incomplete or non-finite" });
|
|
3477
|
+
}
|
|
3478
|
+
const verticalCount = values[3];
|
|
3479
|
+
const horizontalCount = values[4];
|
|
3480
|
+
const photometricType = values[5];
|
|
3481
|
+
if (verticalCount === void 0 || horizontalCount === void 0 || photometricType === void 0) {
|
|
3482
|
+
return err({ code: "invalid-ies", reason: "numeric header is incomplete or non-finite" });
|
|
3483
|
+
}
|
|
3484
|
+
if (photometricType !== 1) {
|
|
3485
|
+
return err({
|
|
3486
|
+
code: "unsupported-photometric-type",
|
|
3487
|
+
reason: `photometric type ${photometricType} is not Type C`
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
if (!Number.isInteger(verticalCount) || !Number.isInteger(horizontalCount) || verticalCount < 2 || horizontalCount < 1) {
|
|
3491
|
+
return err({ code: "invalid-ies", reason: "angle counts are invalid" });
|
|
3492
|
+
}
|
|
3493
|
+
const angleOffset = 12;
|
|
3494
|
+
const verticalEnd = angleOffset + verticalCount;
|
|
3495
|
+
const horizontalEnd = verticalEnd + horizontalCount;
|
|
3496
|
+
const candelaEnd = horizontalEnd + verticalCount * horizontalCount;
|
|
3497
|
+
if (values.length < candelaEnd) {
|
|
3498
|
+
return err({ code: "invalid-ies", reason: "angle or candela table is incomplete" });
|
|
3499
|
+
}
|
|
3500
|
+
const verticalAnglesDeg = values.slice(angleOffset, verticalEnd);
|
|
3501
|
+
const horizontalAnglesDeg = values.slice(verticalEnd, horizontalEnd);
|
|
3502
|
+
const candelaMultiplier = values[2];
|
|
3503
|
+
if (candelaMultiplier === void 0) {
|
|
3504
|
+
return err({ code: "invalid-ies", reason: "numeric header is incomplete or non-finite" });
|
|
3505
|
+
}
|
|
3506
|
+
const candela = values.slice(horizontalEnd, candelaEnd).map((value) => value * candelaMultiplier);
|
|
3507
|
+
if (!allFinite(verticalAnglesDeg) || !allFinite(horizontalAnglesDeg) || !allFinite(candela) || verticalAnglesDeg[0] !== 0 || verticalAnglesDeg[verticalAnglesDeg.length - 1] !== 180 || horizontalAnglesDeg[0] !== 0) {
|
|
3508
|
+
return err({ code: "invalid-ies", reason: "Type C angles or candela values are invalid" });
|
|
3509
|
+
}
|
|
3510
|
+
return ok({ tilt: "NONE", verticalAnglesDeg, horizontalAnglesDeg, candela });
|
|
3511
|
+
}
|
|
3512
|
+
function horizontalTable(source) {
|
|
3513
|
+
const angles = [...source.horizontalAnglesDeg];
|
|
3514
|
+
const values = [...source.candela];
|
|
3515
|
+
const verticalCount = source.verticalAnglesDeg.length;
|
|
3516
|
+
const lastAngle = angles.at(-1);
|
|
3517
|
+
if (lastAngle === void 0) return { angles, values };
|
|
3518
|
+
if (lastAngle < 360) {
|
|
3519
|
+
for (let index = angles.length - 2; index > 0; index--) {
|
|
3520
|
+
const angle = angles[index];
|
|
3521
|
+
if (angle === void 0) continue;
|
|
3522
|
+
angles.push(360 - angle);
|
|
3523
|
+
const row = source.horizontalAnglesDeg.length - 1 - index;
|
|
3524
|
+
values.push(
|
|
3525
|
+
...source.candela.slice(row * verticalCount, row * verticalCount + verticalCount)
|
|
3526
|
+
);
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
return { angles, values };
|
|
3530
|
+
}
|
|
3531
|
+
function interpolate(values, angles, angle, verticalIndex, verticalCount) {
|
|
3532
|
+
const wrapped = (angle % 360 + 360) % 360;
|
|
3533
|
+
const last = angles.length - 1;
|
|
3534
|
+
const finalAngle = angles[last];
|
|
3535
|
+
const firstAngle = angles[0];
|
|
3536
|
+
if (finalAngle === void 0 || firstAngle === void 0) return Number.NaN;
|
|
3537
|
+
for (let index = 0; index < last; index++) {
|
|
3538
|
+
const left = angles[index];
|
|
3539
|
+
const right = angles[index + 1];
|
|
3540
|
+
if (left === void 0 || right === void 0) continue;
|
|
3541
|
+
if (wrapped < left || wrapped > right) continue;
|
|
3542
|
+
const span2 = right - left;
|
|
3543
|
+
const factor2 = span2 === 0 ? 0 : (wrapped - left) / span2;
|
|
3544
|
+
const a = values[index * verticalCount + verticalIndex] ?? 0;
|
|
3545
|
+
const b = values[(index + 1) * verticalCount + verticalIndex] ?? 0;
|
|
3546
|
+
return a + (b - a) * factor2;
|
|
3547
|
+
}
|
|
3548
|
+
const first = values[verticalIndex] ?? 0;
|
|
3549
|
+
const finalRow = (angles.length - 1) * verticalCount + verticalIndex;
|
|
3550
|
+
const final = values[finalRow] ?? 0;
|
|
3551
|
+
const span = 360 - finalAngle + firstAngle;
|
|
3552
|
+
const factor = span === 0 ? 0 : (wrapped - finalAngle + 360) / span;
|
|
3553
|
+
return final + (first - final) * factor;
|
|
3554
|
+
}
|
|
3555
|
+
function toFloat16(value) {
|
|
3556
|
+
if (value === 0) return 0;
|
|
3557
|
+
const sign = value < 0 ? 32768 : 0;
|
|
3558
|
+
const absolute = Math.abs(value);
|
|
3559
|
+
if (!Number.isFinite(absolute)) return sign | 31744;
|
|
3560
|
+
const exponent = Math.floor(Math.log2(absolute));
|
|
3561
|
+
if (exponent < -14) return sign | Math.round(absolute / 2 ** -24);
|
|
3562
|
+
if (exponent > 15) return sign | 31744;
|
|
3563
|
+
const mantissa = Math.round((absolute / 2 ** exponent - 1) * 1024);
|
|
3564
|
+
return sign | exponent + 15 << 10 | Math.min(mantissa, 1023);
|
|
3565
|
+
}
|
|
3566
|
+
function readFloat16LE(bytes2, offset) {
|
|
3567
|
+
const bits = (bytes2[offset] ?? 0) | (bytes2[offset + 1] ?? 0) << 8;
|
|
3568
|
+
const sign = (bits & 32768) === 0 ? 1 : -1;
|
|
3569
|
+
const exponent = bits >>> 10 & 31;
|
|
3570
|
+
const fraction = bits & 1023;
|
|
3571
|
+
if (exponent === 0) return sign * 2 ** -14 * (fraction / 2 ** 10);
|
|
3572
|
+
if (exponent === 31) return fraction === 0 ? sign * Infinity : Number.NaN;
|
|
3573
|
+
return sign * 2 ** (exponent - 15) * (1 + fraction / 2 ** 10);
|
|
3574
|
+
}
|
|
3575
|
+
function resampleTypeC(source) {
|
|
3576
|
+
const table = horizontalTable(source);
|
|
3577
|
+
const verticalCount = source.verticalAnglesDeg.length;
|
|
3578
|
+
const output = new Uint8Array(IES_PROFILE_WIDTH * IES_PROFILE_HEIGHT * 2);
|
|
3579
|
+
let peak = 0;
|
|
3580
|
+
const samples = [];
|
|
3581
|
+
for (let y = 0; y < IES_PROFILE_HEIGHT; y++) {
|
|
3582
|
+
const vertical = y / (IES_PROFILE_HEIGHT - 1) * 180;
|
|
3583
|
+
let lower = 0;
|
|
3584
|
+
while (lower + 1 < verticalCount && (source.verticalAnglesDeg[lower + 1] ?? 0) < vertical)
|
|
3585
|
+
lower++;
|
|
3586
|
+
const upper = Math.min(lower + 1, verticalCount - 1);
|
|
3587
|
+
const left = source.verticalAnglesDeg[lower] ?? 0;
|
|
3588
|
+
const right = source.verticalAnglesDeg[upper] ?? 0;
|
|
3589
|
+
const factor = right === left ? 0 : (vertical - left) / (right - left);
|
|
3590
|
+
for (let x = 0; x < IES_PROFILE_WIDTH; x++) {
|
|
3591
|
+
const horizontal = x / IES_PROFILE_WIDTH * 360;
|
|
3592
|
+
const low = interpolate(table.values, table.angles, horizontal, lower, verticalCount);
|
|
3593
|
+
const high = interpolate(table.values, table.angles, horizontal, upper, verticalCount);
|
|
3594
|
+
const value = low + (high - low) * factor;
|
|
3595
|
+
samples.push(Math.max(0, value));
|
|
3596
|
+
peak = Math.max(peak, value);
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
const divisor = peak > 0 ? peak : 1;
|
|
3600
|
+
for (let index = 0; index < samples.length; index++) {
|
|
3601
|
+
const bits = toFloat16((samples[index] ?? 0) / divisor);
|
|
3602
|
+
output[index * 2] = bits & 255;
|
|
3603
|
+
output[index * 2 + 1] = bits >>> 8;
|
|
3604
|
+
}
|
|
3605
|
+
return output;
|
|
3606
|
+
}
|
|
3607
|
+
|
|
3608
|
+
// src/ies/ies-importer.ts
|
|
3609
|
+
function isRecord(value) {
|
|
3610
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3611
|
+
}
|
|
3612
|
+
function decodeFloat16(bytes2, offset) {
|
|
3613
|
+
const bits = (bytes2[offset] ?? 0) | (bytes2[offset + 1] ?? 0) << 8;
|
|
3614
|
+
const sign = (bits & 32768) === 0 ? 1 : -1;
|
|
3615
|
+
const exponent = bits >>> 10 & 31;
|
|
3616
|
+
const fraction = bits & 1023;
|
|
3617
|
+
if (exponent === 0) return sign * 2 ** -14 * (fraction / 2 ** 10);
|
|
3618
|
+
if (exponent === 31) return fraction === 0 ? sign * Infinity : Number.NaN;
|
|
3619
|
+
return sign * 2 ** (exponent - 15) * (1 + fraction / 2 ** 10);
|
|
3620
|
+
}
|
|
3621
|
+
function validateIesProfilePayload(value) {
|
|
3622
|
+
if (!isRecord(value) || value.kind !== "ies-profile") {
|
|
3623
|
+
return err(new Error("IES payload kind must be ies-profile"));
|
|
3624
|
+
}
|
|
3625
|
+
const data = value.data;
|
|
3626
|
+
if (!(data instanceof Uint8Array) || data.byteLength !== IES_PROFILE_BYTE_LENGTH) {
|
|
3627
|
+
return err(
|
|
3628
|
+
new Error(
|
|
3629
|
+
`IES payload must contain ${IES_PROFILE_WIDTH}x${IES_PROFILE_HEIGHT} little-endian f16 samples`
|
|
3630
|
+
)
|
|
3631
|
+
);
|
|
3632
|
+
}
|
|
3633
|
+
for (let offset = 0; offset < data.byteLength; offset += 2) {
|
|
3634
|
+
if (!Number.isFinite(decodeFloat16(data, offset))) {
|
|
3635
|
+
return err(new Error("IES payload contains a non-finite f16 sample"));
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
return ok(value);
|
|
3639
|
+
}
|
|
3640
|
+
function sourceValidationError(ctx, reason) {
|
|
3641
|
+
return new ImportError({
|
|
3642
|
+
code: "source-validation-failed",
|
|
3643
|
+
expected: "LM-63 Type C source with TILT=NONE",
|
|
3644
|
+
hint: IMPORT_ERROR_HINTS["source-validation-failed"],
|
|
3645
|
+
detail: {
|
|
3646
|
+
diagnostics: [
|
|
3647
|
+
{
|
|
3648
|
+
code: "ies-source-invalid",
|
|
3649
|
+
severity: "error",
|
|
3650
|
+
sourcePath: ctx.source,
|
|
3651
|
+
sourceRange: { start: 0, end: 0, line: 1, column: 1 },
|
|
3652
|
+
rule: "LM-63 Type C TILT=NONE",
|
|
3653
|
+
expected: "LM-63 Type C source with TILT=NONE",
|
|
3654
|
+
actual: reason,
|
|
3655
|
+
hint: "repair the IES source and rerun the build-time importer"
|
|
3656
|
+
}
|
|
3657
|
+
]
|
|
3658
|
+
}
|
|
3659
|
+
});
|
|
3660
|
+
}
|
|
3661
|
+
async function importIes(ctx) {
|
|
3662
|
+
const source = await ctx.readSource();
|
|
3663
|
+
if (!source.ok) {
|
|
3664
|
+
return {
|
|
3665
|
+
ok: false,
|
|
3666
|
+
error: new ImportError({
|
|
3667
|
+
code: "source-read-failed",
|
|
3668
|
+
expected: `readable IES source at ${ctx.source}`,
|
|
3669
|
+
hint: IMPORT_ERROR_HINTS["source-read-failed"],
|
|
3670
|
+
detail: { source: ctx.source, reason: String(source.error) }
|
|
3671
|
+
})
|
|
3672
|
+
};
|
|
3673
|
+
}
|
|
3674
|
+
const parsed = parseLm63TypeC(new TextDecoder().decode(source.value));
|
|
3675
|
+
if (!parsed.ok) return { ok: false, error: sourceValidationError(ctx, parsed.error.reason) };
|
|
3676
|
+
const declaration = ctx.subAssets.find((asset) => asset.kind === "ies-profile");
|
|
3677
|
+
if (declaration === void 0) {
|
|
3678
|
+
return {
|
|
3679
|
+
ok: false,
|
|
3680
|
+
error: sourceValidationError(ctx, "missing ies-profile sub-asset declaration")
|
|
3681
|
+
};
|
|
3682
|
+
}
|
|
3683
|
+
const data = resampleTypeC(parsed.value);
|
|
3684
|
+
const payload = { kind: "ies-profile", data };
|
|
3685
|
+
return {
|
|
3686
|
+
ok: true,
|
|
3687
|
+
value: {
|
|
3688
|
+
assets: [
|
|
3689
|
+
{
|
|
3690
|
+
guid: declaration.guid,
|
|
3691
|
+
kind: "ies-profile",
|
|
3692
|
+
payload,
|
|
3693
|
+
refs: [],
|
|
3694
|
+
artifacts: {
|
|
3695
|
+
body: {
|
|
3696
|
+
mediaType: "application/octet-stream",
|
|
3697
|
+
assetCodec: { name: "forgeax-ies-profile", version: "1" },
|
|
3698
|
+
bytes: data
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
],
|
|
3703
|
+
sourceDependencies: [ctx.source]
|
|
3704
|
+
}
|
|
3705
|
+
};
|
|
3706
|
+
}
|
|
3707
|
+
var iesImporter = {
|
|
3708
|
+
key: "ies",
|
|
3709
|
+
import: importIes
|
|
3710
|
+
};
|
|
3711
|
+
|
|
3712
|
+
// src/importer-registry.ts
|
|
3713
|
+
var ImporterRegistry = class {
|
|
3714
|
+
importers = /* @__PURE__ */ new Map();
|
|
3715
|
+
/**
|
|
3716
|
+
* Register an importer for its `importer.key`. Fail-fast on a malformed
|
|
3717
|
+
* importer (charter P3); idempotent on a repeated key (last write wins).
|
|
3718
|
+
*
|
|
3719
|
+
* @param importer the `{ key, import }` object to register.
|
|
3720
|
+
* @throws TypeError when `importer.key` is empty or `importer.import` is not
|
|
3721
|
+
* a function - a wire-time misconfiguration the host must fix.
|
|
3722
|
+
*/
|
|
3723
|
+
register(importer) {
|
|
3724
|
+
if (typeof importer.key !== "string" || importer.key.length === 0) {
|
|
3725
|
+
throw new TypeError(
|
|
3726
|
+
`ImporterRegistry.register: importer.key must be a non-empty string (got ${JSON.stringify(importer.key)})`
|
|
3727
|
+
);
|
|
3728
|
+
}
|
|
3729
|
+
if (typeof importer.import !== "function") {
|
|
3730
|
+
throw new TypeError(
|
|
3731
|
+
`ImporterRegistry.register: importer.import must be a function for key "${importer.key}"`
|
|
3732
|
+
);
|
|
3733
|
+
}
|
|
3734
|
+
this.importers.set(importer.key, importer);
|
|
3735
|
+
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Look up the importer registered for `key`. Returns `undefined` when no
|
|
3738
|
+
* importer is wired - the import runner maps that to a structured
|
|
3739
|
+
* `ImportError(code='importer-not-registered')` with the registered keys in
|
|
3740
|
+
* `.detail.registeredImporters` (charter P3).
|
|
3741
|
+
*/
|
|
3742
|
+
get(key) {
|
|
3743
|
+
return this.importers.get(key);
|
|
3744
|
+
}
|
|
3745
|
+
/**
|
|
3746
|
+
* The importer keys currently wired, in insertion order. Fed into the
|
|
3747
|
+
* `importer-not-registered` error `.detail.registeredImporters` so AI users
|
|
3748
|
+
* see exactly what is injectable.
|
|
3749
|
+
*/
|
|
3750
|
+
registeredImporters() {
|
|
3751
|
+
return [...this.importers.keys()];
|
|
3752
|
+
}
|
|
3753
|
+
/** Project the first registered producer capability into the runner context. */
|
|
3754
|
+
contextCapabilities() {
|
|
3755
|
+
for (const importer of this.importers.values()) {
|
|
3756
|
+
const decoder = importer.capabilities?.decodeImage;
|
|
3757
|
+
if (decoder !== void 0) return { decodeImage: decoder };
|
|
3758
|
+
}
|
|
3759
|
+
return {};
|
|
3760
|
+
}
|
|
3761
|
+
/** Ask the registered producer whether a declaration has a Catalog product. */
|
|
3762
|
+
shouldPublishCatalog(input) {
|
|
3763
|
+
return this.get(input.importer)?.capabilities?.catalog?.publish?.({
|
|
3764
|
+
importSettings: input.importSettings,
|
|
3765
|
+
subAssets: input.subAssets
|
|
3766
|
+
}) ?? true;
|
|
3767
|
+
}
|
|
3768
|
+
};
|
|
3769
|
+
function isRecord2(value) {
|
|
3770
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3771
|
+
}
|
|
3772
|
+
function stable2(value) {
|
|
3773
|
+
if (value instanceof ArrayBuffer) {
|
|
3774
|
+
return `ArrayBuffer:${JSON.stringify(Array.from(new Uint8Array(value)))}`;
|
|
3775
|
+
}
|
|
3776
|
+
if (ArrayBuffer.isView(value)) {
|
|
3777
|
+
return `${value.constructor.name}:${JSON.stringify(
|
|
3778
|
+
Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength))
|
|
3779
|
+
)}`;
|
|
3780
|
+
}
|
|
3781
|
+
if (Array.isArray(value)) return `[${value.map(stable2).join(",")}]`;
|
|
3782
|
+
if (value !== null && typeof value === "object") {
|
|
3783
|
+
const record2 = value;
|
|
3784
|
+
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stable2(record2[key])}`).join(",")}}`;
|
|
3785
|
+
}
|
|
3786
|
+
return JSON.stringify(value) ?? "null";
|
|
3787
|
+
}
|
|
3788
|
+
function digest2(value) {
|
|
3789
|
+
return `sha256:${createHash("sha256").update(stable2(value)).digest("hex")}`;
|
|
3790
|
+
}
|
|
3791
|
+
function generationFromDigest(value) {
|
|
3792
|
+
const parsed = Number.parseInt(value.slice("sha256:".length, "sha256:".length + 8), 16);
|
|
3793
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
3794
|
+
}
|
|
3795
|
+
function reasonOf(error) {
|
|
3796
|
+
return error instanceof Error ? error.message : String(error);
|
|
3797
|
+
}
|
|
3798
|
+
async function collectPackFiles(assetRoots) {
|
|
3799
|
+
const files = /* @__PURE__ */ new Set();
|
|
3800
|
+
async function visit(directory) {
|
|
3801
|
+
let entries;
|
|
3802
|
+
try {
|
|
3803
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
3804
|
+
} catch (error) {
|
|
3805
|
+
return err({
|
|
3806
|
+
code: "scriptable-pack-file-root-unreadable",
|
|
3807
|
+
expected: "every configured ScriptablePack asset root to be readable",
|
|
3808
|
+
hint: "restore the asset root or configure a readable directory, then retry the ScriptablePack build",
|
|
3809
|
+
detail: { root: directory, reason: reasonOf(error) }
|
|
3810
|
+
});
|
|
3811
|
+
}
|
|
3812
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
3813
|
+
const child = resolve(directory, entry.name);
|
|
3814
|
+
if (entry.isDirectory()) {
|
|
3815
|
+
const nested = await visit(child);
|
|
3816
|
+
if (!nested.ok) return nested;
|
|
3817
|
+
} else if (entry.isFile() && entry.name.endsWith(".pack.json")) {
|
|
3818
|
+
files.add(child);
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
return ok(void 0);
|
|
3822
|
+
}
|
|
3823
|
+
for (const rawRoot of [...new Set(assetRoots.map((root) => resolve(root)))].sort(
|
|
3824
|
+
(a, b) => a.localeCompare(b)
|
|
3825
|
+
)) {
|
|
3826
|
+
let info;
|
|
3827
|
+
try {
|
|
3828
|
+
info = await stat(rawRoot);
|
|
3829
|
+
} catch (error) {
|
|
3830
|
+
return err({
|
|
3831
|
+
code: "scriptable-pack-file-root-unreadable",
|
|
3832
|
+
expected: "every configured ScriptablePack asset root to exist and be readable",
|
|
3833
|
+
hint: "restore the asset root or configure a readable directory, then retry the ScriptablePack build",
|
|
3834
|
+
detail: { root: rawRoot, reason: reasonOf(error) }
|
|
3835
|
+
});
|
|
3836
|
+
}
|
|
3837
|
+
if (info.isFile()) {
|
|
3838
|
+
if (rawRoot.endsWith(".pack.json")) files.add(rawRoot);
|
|
3839
|
+
continue;
|
|
3840
|
+
}
|
|
3841
|
+
if (!info.isDirectory()) {
|
|
3842
|
+
return err({
|
|
3843
|
+
code: "scriptable-pack-file-root-unreadable",
|
|
3844
|
+
expected: "every configured ScriptablePack asset root to be a file or directory",
|
|
3845
|
+
hint: "configure an asset root containing ordinary .pack.json files, then retry the ScriptablePack build",
|
|
3846
|
+
detail: { root: rawRoot, reason: "root is neither a file nor a directory" }
|
|
3847
|
+
});
|
|
3848
|
+
}
|
|
3849
|
+
const visited = await visit(rawRoot);
|
|
3850
|
+
if (!visited.ok) return visited;
|
|
3851
|
+
}
|
|
3852
|
+
return ok([...files].sort((left, right) => left.localeCompare(right)));
|
|
3853
|
+
}
|
|
3854
|
+
function invalidPack(path, errors) {
|
|
3855
|
+
return {
|
|
3856
|
+
code: "scriptable-pack-file-invalid",
|
|
3857
|
+
expected: "a schema-valid ordinary .pack.json package",
|
|
3858
|
+
hint: "repair the Pack JSON against the package schema, then retry the ScriptablePack build",
|
|
3859
|
+
detail: { path, ajvErrors: errors }
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
function assetFromRow(path, row) {
|
|
3863
|
+
if (!isScriptablePackAssetKind$1(row.kind)) {
|
|
3864
|
+
return err({
|
|
3865
|
+
code: "scriptable-pack-file-asset-invalid",
|
|
3866
|
+
expected: "an ordinary ScriptablePack Asset kind from SCRIPTABLE_PACK_ASSET_KINDS",
|
|
3867
|
+
hint: "use an ordinary engine Asset kind or keep the custom payload outside this Asset snapshot source",
|
|
3868
|
+
detail: { path, guid: row.guid, reason: `unsupported kind ${JSON.stringify(row.kind)}` }
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3871
|
+
if (!isRecord2(row.payload)) {
|
|
3872
|
+
return err({
|
|
3873
|
+
code: "scriptable-pack-file-asset-invalid",
|
|
3874
|
+
expected: "the Pack row payload to be a JSON object",
|
|
3875
|
+
hint: "write a complete ordinary Asset payload in the .pack.json row, then retry the ScriptablePack build",
|
|
3876
|
+
detail: { path, guid: row.guid, reason: "payload is not an object" }
|
|
3877
|
+
});
|
|
3878
|
+
}
|
|
3879
|
+
const payloadKind = row.payload.kind;
|
|
3880
|
+
if (payloadKind !== void 0 && payloadKind !== row.kind) {
|
|
3881
|
+
return err({
|
|
3882
|
+
code: "scriptable-pack-file-asset-invalid",
|
|
3883
|
+
expected: "the row kind and payload.kind to agree",
|
|
3884
|
+
hint: "repair the duplicated kind discriminant in the .pack.json row, then retry the ScriptablePack build",
|
|
3885
|
+
detail: {
|
|
3886
|
+
path,
|
|
3887
|
+
guid: row.guid,
|
|
3888
|
+
reason: `row kind ${JSON.stringify(row.kind)} does not match payload.kind ${JSON.stringify(payloadKind)}`
|
|
3889
|
+
}
|
|
3890
|
+
});
|
|
3891
|
+
}
|
|
3892
|
+
const asset = { ...row.payload, kind: row.kind };
|
|
3893
|
+
return ok({ asset, digest: digest2(asset) });
|
|
3894
|
+
}
|
|
3895
|
+
async function indexPackFiles(assetRoots) {
|
|
3896
|
+
const files = await collectPackFiles(assetRoots);
|
|
3897
|
+
if (!files.ok) return files;
|
|
3898
|
+
const byGuid = /* @__PURE__ */ new Map();
|
|
3899
|
+
const pathsByGuid = /* @__PURE__ */ new Map();
|
|
3900
|
+
const documents = [];
|
|
3901
|
+
for (const path of files.value) {
|
|
3902
|
+
let body;
|
|
3903
|
+
try {
|
|
3904
|
+
body = await readFile(path, "utf8");
|
|
3905
|
+
} catch (error) {
|
|
3906
|
+
return err({
|
|
3907
|
+
code: "scriptable-pack-file-unreadable",
|
|
3908
|
+
expected: "a readable .pack.json file",
|
|
3909
|
+
hint: "restore the .pack.json file, then retry the ScriptablePack build",
|
|
3910
|
+
detail: { path, reason: reasonOf(error) }
|
|
3911
|
+
});
|
|
3912
|
+
}
|
|
3913
|
+
let parsed;
|
|
3914
|
+
try {
|
|
3915
|
+
parsed = JSON.parse(body);
|
|
3916
|
+
} catch (error) {
|
|
3917
|
+
return err({
|
|
3918
|
+
code: "scriptable-pack-file-json-invalid",
|
|
3919
|
+
expected: "a parseable JSON .pack.json file",
|
|
3920
|
+
hint: "repair or restore the .pack.json file, then retry the ScriptablePack build",
|
|
3921
|
+
detail: { path, reason: reasonOf(error) }
|
|
3922
|
+
});
|
|
3923
|
+
}
|
|
3924
|
+
if (!validatePack(parsed)) {
|
|
3925
|
+
return err(
|
|
3926
|
+
invalidPack(
|
|
3927
|
+
path,
|
|
3928
|
+
(validatePack.errors ?? []).map((error) => ({
|
|
3929
|
+
instancePath: error.instancePath,
|
|
3930
|
+
message: error.message ?? "unknown schema validation error"
|
|
3931
|
+
}))
|
|
3932
|
+
)
|
|
3933
|
+
);
|
|
3934
|
+
}
|
|
3935
|
+
const document = parsed;
|
|
3936
|
+
documents.push(document);
|
|
3937
|
+
for (const row of document.assets) {
|
|
3938
|
+
const existingPath = pathsByGuid.get(row.guid.toLowerCase());
|
|
3939
|
+
if (existingPath !== void 0) {
|
|
3940
|
+
return err({
|
|
3941
|
+
code: "scriptable-pack-file-guid-collision",
|
|
3942
|
+
expected: "each ordinary Pack asset GUID to be declared by exactly one .pack.json file",
|
|
3943
|
+
hint: "remove the duplicate GUID declaration or keep one authoritative .pack.json package, then retry",
|
|
3944
|
+
detail: { guid: row.guid.toLowerCase(), paths: [existingPath, path] }
|
|
3945
|
+
});
|
|
3946
|
+
}
|
|
3947
|
+
const asset = assetFromRow(path, row);
|
|
3948
|
+
if (!asset.ok) return asset;
|
|
3949
|
+
const key = row.guid.toLowerCase();
|
|
3950
|
+
pathsByGuid.set(key, path);
|
|
3951
|
+
byGuid.set(key, asset.value);
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
const sourceDigest = digest2(
|
|
3955
|
+
[...documents].sort((left, right) => stable2(left).localeCompare(stable2(right)))
|
|
3956
|
+
);
|
|
3957
|
+
return ok({
|
|
3958
|
+
generation: generationFromDigest(sourceDigest),
|
|
3959
|
+
assets: byGuid
|
|
3960
|
+
});
|
|
3961
|
+
}
|
|
3962
|
+
function createScriptablePackFileAssetSnapshotSource(options) {
|
|
3963
|
+
const index = indexPackFiles(options.assetRoots);
|
|
3964
|
+
return {
|
|
3965
|
+
async readByGuid(guid) {
|
|
3966
|
+
const key = AssetGuid$1.format(guid).toLowerCase();
|
|
3967
|
+
const indexed = await index;
|
|
3968
|
+
if (!indexed.ok) return indexed;
|
|
3969
|
+
const asset = indexed.value.assets.get(key);
|
|
3970
|
+
if (asset === void 0) {
|
|
3971
|
+
return err({
|
|
3972
|
+
code: "asset-not-found",
|
|
3973
|
+
expected: `an ordinary .pack.json asset with GUID ${key} under the configured asset roots`,
|
|
3974
|
+
hint: "add the dependency to an asset root or declare it as a ScriptablePack external reference, then retry",
|
|
3975
|
+
detail: { guid: key }
|
|
3976
|
+
});
|
|
3977
|
+
}
|
|
3978
|
+
return ok({
|
|
3979
|
+
asset: structuredClone(asset.asset),
|
|
3980
|
+
generation: indexed.value.generation,
|
|
3981
|
+
digest: asset.digest
|
|
3982
|
+
});
|
|
3983
|
+
}
|
|
3984
|
+
};
|
|
3985
|
+
}
|
|
3986
|
+
function stable3(value) {
|
|
3987
|
+
if (ArrayBuffer.isView(value)) {
|
|
3988
|
+
return `${value.constructor.name}:${JSON.stringify(Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength)))}`;
|
|
3989
|
+
}
|
|
3990
|
+
if (Array.isArray(value)) return `[${value.map(stable3).join(",")}]`;
|
|
3991
|
+
if (value !== null && typeof value === "object") {
|
|
3992
|
+
const record2 = value;
|
|
3993
|
+
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${stable3(record2[key])}`).join(",")}}`;
|
|
2541
3994
|
}
|
|
3995
|
+
return JSON.stringify(value) ?? "null";
|
|
3996
|
+
}
|
|
3997
|
+
async function assetDigest(asset) {
|
|
3998
|
+
const bytes2 = new TextEncoder().encode(stable3(asset));
|
|
3999
|
+
const digest3 = await globalThis.crypto.subtle.digest("SHA-256", bytes2);
|
|
4000
|
+
return `sha256:${Array.from(new Uint8Array(digest3), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
4001
|
+
}
|
|
4002
|
+
function cycleError(stack, owner, guid) {
|
|
4003
|
+
const cycleStart = stack.indexOf(owner);
|
|
4004
|
+
const cycle = [...stack.slice(cycleStart), owner];
|
|
2542
4005
|
return {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
4006
|
+
code: "pack-content-dependency-stalled",
|
|
4007
|
+
expected: "the content dependency worklist to make progress",
|
|
4008
|
+
hint: "inspect the waiting GUID and pending subjects, then break the content-read cycle",
|
|
4009
|
+
detail: { waitingGuids: [guid], pendingSubjects: cycle, iterations: 1 }
|
|
2547
4010
|
};
|
|
2548
4011
|
}
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
...sourceIdentityFor === void 0 ? {} : { sourceIdentityFor }
|
|
4012
|
+
function missingOutputError(owner, guid) {
|
|
4013
|
+
return {
|
|
4014
|
+
code: "pack-source-output-invalid",
|
|
4015
|
+
expected: `owner ${owner} to stage every declared output including ${guid}`,
|
|
4016
|
+
hint: "return one output for every GUID declared by the staged owner",
|
|
4017
|
+
detail: { missingGuids: [guid], unexpectedSourceKeys: [], kindMismatches: [] }
|
|
2556
4018
|
};
|
|
2557
|
-
return buildCatalogProjection(roots, options);
|
|
2558
4019
|
}
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
if (
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
);
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
);
|
|
4020
|
+
function createScriptablePackStagedAssetSnapshotSource(options) {
|
|
4021
|
+
const owners = options.declaredExternalOutputs === void 0 || options.declaredExternalOutputs.length === 0 ? options.owners : [
|
|
4022
|
+
{
|
|
4023
|
+
id: "<declared-pack-external>",
|
|
4024
|
+
guids: options.declaredExternalOutputs.map((output) => output.guid),
|
|
4025
|
+
async build() {
|
|
4026
|
+
return ok(options.declaredExternalOutputs ?? []);
|
|
4027
|
+
}
|
|
4028
|
+
},
|
|
4029
|
+
...options.owners
|
|
4030
|
+
];
|
|
4031
|
+
const ownerByGuid = /* @__PURE__ */ new Map();
|
|
4032
|
+
for (const owner of owners) {
|
|
4033
|
+
if (owner.id.trim().length === 0) throw new TypeError("staged owner id must be non-empty");
|
|
4034
|
+
for (const guid of owner.guids) {
|
|
4035
|
+
const key = AssetGuid$1.format(guid).toLowerCase();
|
|
4036
|
+
const existing = ownerByGuid.get(key);
|
|
4037
|
+
if (existing !== void 0) {
|
|
4038
|
+
throw new TypeError(`staged GUID ${key} is owned by both ${existing.id} and ${owner.id}`);
|
|
4039
|
+
}
|
|
4040
|
+
ownerByGuid.set(key, owner);
|
|
2581
4041
|
}
|
|
2582
|
-
this.importers.set(importer.key, importer);
|
|
2583
|
-
}
|
|
2584
|
-
/**
|
|
2585
|
-
* Look up the importer registered for `key`. Returns `undefined` when no
|
|
2586
|
-
* importer is wired - the import runner maps that to a structured
|
|
2587
|
-
* `ImportError(code='importer-not-registered')` with the registered keys in
|
|
2588
|
-
* `.detail.registeredImporters` (charter P3).
|
|
2589
|
-
*/
|
|
2590
|
-
get(key) {
|
|
2591
|
-
return this.importers.get(key);
|
|
2592
|
-
}
|
|
2593
|
-
/**
|
|
2594
|
-
* The importer keys currently wired, in insertion order. Fed into the
|
|
2595
|
-
* `importer-not-registered` error `.detail.registeredImporters` so AI users
|
|
2596
|
-
* see exactly what is injectable.
|
|
2597
|
-
*/
|
|
2598
|
-
registeredImporters() {
|
|
2599
|
-
return [...this.importers.keys()];
|
|
2600
4042
|
}
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
4043
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
4044
|
+
const builds = /* @__PURE__ */ new Map();
|
|
4045
|
+
const sourceFor = (stack) => ({
|
|
4046
|
+
async readByGuid(guid) {
|
|
4047
|
+
const key = AssetGuid$1.format(guid).toLowerCase();
|
|
4048
|
+
const cached = snapshots.get(key);
|
|
4049
|
+
if (cached !== void 0) return ok(structuredClone(cached));
|
|
4050
|
+
const owner = ownerByGuid.get(key);
|
|
4051
|
+
if (owner === void 0) {
|
|
4052
|
+
return err(
|
|
4053
|
+
new AssetError({
|
|
4054
|
+
code: "asset-not-imported",
|
|
4055
|
+
expected: "a staged local owner for the requested GUID",
|
|
4056
|
+
hint: "declare the local ScriptablePack output before rebuilding the generation"
|
|
4057
|
+
})
|
|
4058
|
+
);
|
|
4059
|
+
}
|
|
4060
|
+
if (stack.includes(owner.id)) return err(cycleError(stack, owner.id, key));
|
|
4061
|
+
let building = builds.get(owner.id);
|
|
4062
|
+
if (building === void 0) {
|
|
4063
|
+
building = (async () => {
|
|
4064
|
+
const built2 = await owner.build(sourceFor([...stack, owner.id]));
|
|
4065
|
+
if (!built2.ok) {
|
|
4066
|
+
builds.delete(owner.id);
|
|
4067
|
+
return built2;
|
|
4068
|
+
}
|
|
4069
|
+
const next = /* @__PURE__ */ new Map();
|
|
4070
|
+
for (const output of built2.value) {
|
|
4071
|
+
const outputGuid = AssetGuid$1.format(output.guid).toLowerCase();
|
|
4072
|
+
if (ownerByGuid.get(outputGuid) !== owner) {
|
|
4073
|
+
builds.delete(owner.id);
|
|
4074
|
+
return err(missingOutputError(owner.id, outputGuid));
|
|
4075
|
+
}
|
|
4076
|
+
next.set(outputGuid, {
|
|
4077
|
+
asset: structuredClone(output.asset),
|
|
4078
|
+
generation: options.generation,
|
|
4079
|
+
digest: output.digest ?? await assetDigest(output.asset)
|
|
4080
|
+
});
|
|
4081
|
+
}
|
|
4082
|
+
for (const declared of owner.guids) {
|
|
4083
|
+
const declaredGuid = AssetGuid$1.format(declared).toLowerCase();
|
|
4084
|
+
if (!next.has(declaredGuid)) {
|
|
4085
|
+
builds.delete(owner.id);
|
|
4086
|
+
return err(missingOutputError(owner.id, declaredGuid));
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
for (const [outputGuid, snapshot] of next) snapshots.set(outputGuid, snapshot);
|
|
4090
|
+
return ok(void 0);
|
|
4091
|
+
})();
|
|
4092
|
+
builds.set(owner.id, building);
|
|
4093
|
+
}
|
|
4094
|
+
const built = await building;
|
|
4095
|
+
if (!built.ok) return built;
|
|
4096
|
+
const staged = snapshots.get(key);
|
|
4097
|
+
return staged === void 0 ? err(missingOutputError(owner.id, key)) : ok(structuredClone(staged));
|
|
2606
4098
|
}
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
shouldPublishCatalog(input) {
|
|
2611
|
-
return this.get(input.importer)?.capabilities?.catalog?.publish?.({
|
|
2612
|
-
importSettings: input.importSettings,
|
|
2613
|
-
subAssets: input.subAssets
|
|
2614
|
-
}) ?? true;
|
|
2615
|
-
}
|
|
2616
|
-
};
|
|
4099
|
+
});
|
|
4100
|
+
return sourceFor([]);
|
|
4101
|
+
}
|
|
2617
4102
|
|
|
2618
4103
|
// src/source-package-errors.ts
|
|
2619
4104
|
var SOURCE_PACKAGE_ERROR_POLICY = {
|
|
@@ -2674,6 +4159,9 @@ function importFailureCode(error) {
|
|
|
2674
4159
|
case "source-read-failed":
|
|
2675
4160
|
case "import-internal-error":
|
|
2676
4161
|
case "mesh-material-slot-topology-change":
|
|
4162
|
+
case "mesh-lod-contract-invalid":
|
|
4163
|
+
case "mesh-lod-topology-change":
|
|
4164
|
+
case "mesh-lod-authority-conflict":
|
|
2677
4165
|
case "unknown-source-key":
|
|
2678
4166
|
case "duplicate-source-key":
|
|
2679
4167
|
case "invalid-source-overrides":
|
|
@@ -2687,6 +4175,9 @@ var IMPORT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
2687
4175
|
"import-produced-no-assets",
|
|
2688
4176
|
"guid-mismatch",
|
|
2689
4177
|
"mesh-material-slot-topology-change",
|
|
4178
|
+
"mesh-lod-contract-invalid",
|
|
4179
|
+
"mesh-lod-topology-change",
|
|
4180
|
+
"mesh-lod-authority-conflict",
|
|
2690
4181
|
"import-internal-error",
|
|
2691
4182
|
"source-validation-failed",
|
|
2692
4183
|
"unknown-source-key",
|
|
@@ -2804,7 +4295,7 @@ async function commitSourcePackageDdc(candidate) {
|
|
|
2804
4295
|
async function persistTransport(transport) {
|
|
2805
4296
|
if (transport === void 0) return true;
|
|
2806
4297
|
const directory = dirname(transport.path);
|
|
2807
|
-
const temporary = `${transport.path}.tmp`;
|
|
4298
|
+
const temporary = `${transport.path}.${randomUUID()}.tmp`;
|
|
2808
4299
|
try {
|
|
2809
4300
|
await mkdir(directory, { recursive: true });
|
|
2810
4301
|
if (((await stat(directory)).mode & 146) === 0) {
|
|
@@ -2828,9 +4319,179 @@ function importPublicationFailure(error) {
|
|
|
2828
4319
|
diagnostic: error
|
|
2829
4320
|
};
|
|
2830
4321
|
}
|
|
4322
|
+
function publicationArtifacts(transport) {
|
|
4323
|
+
return Object.fromEntries(
|
|
4324
|
+
(transport?.artifacts ?? []).map((artifact) => [
|
|
4325
|
+
artifact.path,
|
|
4326
|
+
{ mediaType: artifact.mediaType, bytes: artifact.bytes }
|
|
4327
|
+
])
|
|
4328
|
+
);
|
|
4329
|
+
}
|
|
4330
|
+
function publicationContext(input) {
|
|
4331
|
+
return {
|
|
4332
|
+
sourceMeta: "<import-publication>",
|
|
4333
|
+
anchorGuid: input.guid,
|
|
4334
|
+
affectedGuids: input.publishedGuids,
|
|
4335
|
+
producer: "source-package/import-publication",
|
|
4336
|
+
importer: "import-publication"
|
|
4337
|
+
};
|
|
4338
|
+
}
|
|
4339
|
+
function validatePublicationArtifactClosure(input) {
|
|
4340
|
+
const context = publicationContext(input);
|
|
4341
|
+
const pack = input.pack;
|
|
4342
|
+
if (pack === null || typeof pack !== "object" || pack.schemaVersion !== "2.0.0" || pack.kind !== "internal-text-package") {
|
|
4343
|
+
return ok(publicationArtifacts(input.transport));
|
|
4344
|
+
}
|
|
4345
|
+
const assets = pack.assets;
|
|
4346
|
+
if (!Array.isArray(assets)) {
|
|
4347
|
+
return err(
|
|
4348
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4349
|
+
stage: "route-integrity",
|
|
4350
|
+
reason: "published Pack does not contain an assets array"
|
|
4351
|
+
})
|
|
4352
|
+
);
|
|
4353
|
+
}
|
|
4354
|
+
const required = /* @__PURE__ */ new Map();
|
|
4355
|
+
for (const asset of assets) {
|
|
4356
|
+
if (asset === null || typeof asset !== "object") {
|
|
4357
|
+
return err(
|
|
4358
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4359
|
+
stage: "route-integrity",
|
|
4360
|
+
reason: "published Pack contains a non-object asset row"
|
|
4361
|
+
})
|
|
4362
|
+
);
|
|
4363
|
+
}
|
|
4364
|
+
const rawArtifacts = asset.artifacts;
|
|
4365
|
+
if (rawArtifacts === void 0) continue;
|
|
4366
|
+
if (rawArtifacts === null || typeof rawArtifacts !== "object" || Array.isArray(rawArtifacts)) {
|
|
4367
|
+
return err(
|
|
4368
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4369
|
+
stage: "route-integrity",
|
|
4370
|
+
reason: "published Pack contains an invalid asset artifact map"
|
|
4371
|
+
})
|
|
4372
|
+
);
|
|
4373
|
+
}
|
|
4374
|
+
for (const [localKey, rawDescriptor] of Object.entries(
|
|
4375
|
+
rawArtifacts
|
|
4376
|
+
)) {
|
|
4377
|
+
if (rawDescriptor === null || typeof rawDescriptor !== "object") {
|
|
4378
|
+
return err(
|
|
4379
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4380
|
+
stage: "route-integrity",
|
|
4381
|
+
reason: `artifact descriptor ${localKey} is not an object`
|
|
4382
|
+
})
|
|
4383
|
+
);
|
|
4384
|
+
}
|
|
4385
|
+
const descriptor = rawDescriptor;
|
|
4386
|
+
const path = descriptor.path;
|
|
4387
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
4388
|
+
return err(
|
|
4389
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4390
|
+
stage: "route-integrity",
|
|
4391
|
+
reason: `artifact descriptor ${localKey} has no package-relative path`
|
|
4392
|
+
})
|
|
4393
|
+
);
|
|
4394
|
+
}
|
|
4395
|
+
const mediaType = descriptor.mediaType;
|
|
4396
|
+
const byteLength = descriptor.byteLength;
|
|
4397
|
+
const integrityValue = descriptor.integrity;
|
|
4398
|
+
const integrity = integrityValue !== null && typeof integrityValue === "object" ? {
|
|
4399
|
+
algorithm: integrityValue.algorithm,
|
|
4400
|
+
digest: integrityValue.digest
|
|
4401
|
+
} : void 0;
|
|
4402
|
+
if (mediaType !== void 0 && typeof mediaType !== "string" || byteLength !== void 0 && (!Number.isSafeInteger(byteLength) || byteLength < 0) || integrityValue !== void 0 && (integrity === void 0 || typeof integrity.algorithm !== "string" || typeof integrity.digest !== "string")) {
|
|
4403
|
+
return err(
|
|
4404
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4405
|
+
stage: "route-integrity",
|
|
4406
|
+
reason: `artifact descriptor ${path} has invalid metadata`
|
|
4407
|
+
})
|
|
4408
|
+
);
|
|
4409
|
+
}
|
|
4410
|
+
if (required.has(path)) {
|
|
4411
|
+
return err(
|
|
4412
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4413
|
+
stage: "route-integrity",
|
|
4414
|
+
reason: `artifact path ${path} is declared more than once`
|
|
4415
|
+
})
|
|
4416
|
+
);
|
|
4417
|
+
}
|
|
4418
|
+
required.set(path, {
|
|
4419
|
+
...typeof mediaType === "string" ? { mediaType } : {},
|
|
4420
|
+
...typeof byteLength === "number" ? { byteLength } : {},
|
|
4421
|
+
...integrity !== void 0 && typeof integrity.algorithm === "string" && typeof integrity.digest === "string" ? { integrity: { algorithm: integrity.algorithm, digest: integrity.digest } } : {}
|
|
4422
|
+
});
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
const available = /* @__PURE__ */ new Map();
|
|
4426
|
+
const duplicatePaths = [];
|
|
4427
|
+
for (const artifact of input.transport?.artifacts ?? []) {
|
|
4428
|
+
if (available.has(artifact.path)) duplicatePaths.push(artifact.path);
|
|
4429
|
+
available.set(artifact.path, artifact);
|
|
4430
|
+
}
|
|
4431
|
+
const missing = [];
|
|
4432
|
+
const mismatched = [...duplicatePaths.map((path) => `${path}: duplicate body`)];
|
|
4433
|
+
for (const path of available.keys()) {
|
|
4434
|
+
if (!required.has(path)) mismatched.push(`${path}: unexpected body`);
|
|
4435
|
+
}
|
|
4436
|
+
for (const [path, descriptor] of required) {
|
|
4437
|
+
const artifact = available.get(path);
|
|
4438
|
+
if (artifact === void 0) {
|
|
4439
|
+
missing.push(path);
|
|
4440
|
+
continue;
|
|
4441
|
+
}
|
|
4442
|
+
if (!(artifact.bytes instanceof Uint8Array)) {
|
|
4443
|
+
mismatched.push(`${path}: body is not Uint8Array`);
|
|
4444
|
+
continue;
|
|
4445
|
+
}
|
|
4446
|
+
if (descriptor.mediaType !== void 0 && artifact.mediaType !== descriptor.mediaType) {
|
|
4447
|
+
mismatched.push(`${path}: media type mismatch`);
|
|
4448
|
+
}
|
|
4449
|
+
if (descriptor.byteLength !== void 0 && artifact.bytes.byteLength !== descriptor.byteLength) {
|
|
4450
|
+
mismatched.push(`${path}: byte length mismatch`);
|
|
4451
|
+
}
|
|
4452
|
+
if (descriptor.integrity !== void 0) {
|
|
4453
|
+
const actualDigest = `sha256:${createHash("sha256").update(artifact.bytes).digest("hex")}`;
|
|
4454
|
+
if (descriptor.integrity.algorithm !== "sha256" || descriptor.integrity.digest !== actualDigest) {
|
|
4455
|
+
mismatched.push(`${path}: integrity mismatch`);
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
if (missing.length > 0 || mismatched.length > 0) {
|
|
4460
|
+
return err(
|
|
4461
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4462
|
+
stage: "route-integrity",
|
|
4463
|
+
reason: "Pack artifact closure is incomplete or mismatched",
|
|
4464
|
+
...missing.length === 0 ? {} : { missing },
|
|
4465
|
+
...mismatched.length === 0 ? {} : { unexpected: mismatched }
|
|
4466
|
+
})
|
|
4467
|
+
);
|
|
4468
|
+
}
|
|
4469
|
+
if (input.transport !== void 0) {
|
|
4470
|
+
let transportedPack;
|
|
4471
|
+
try {
|
|
4472
|
+
transportedPack = JSON.parse(input.transport.body);
|
|
4473
|
+
} catch {
|
|
4474
|
+
return err(
|
|
4475
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4476
|
+
stage: "route-integrity",
|
|
4477
|
+
reason: "transport body is not valid JSON for the published Pack"
|
|
4478
|
+
})
|
|
4479
|
+
);
|
|
4480
|
+
}
|
|
4481
|
+
if (canonicalDdcJson(transportedPack) !== canonicalDdcJson(pack)) {
|
|
4482
|
+
return err(
|
|
4483
|
+
sourcePackageError("source-package-publication-invalid", context, {
|
|
4484
|
+
stage: "route-integrity",
|
|
4485
|
+
reason: "transport body does not match the published Pack"
|
|
4486
|
+
})
|
|
4487
|
+
);
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
return ok(publicationArtifacts(input.transport));
|
|
4491
|
+
}
|
|
2831
4492
|
function projectImportPublication(input, head, observedAt) {
|
|
2832
|
-
const
|
|
2833
|
-
const revision = { digest, observedAt, rootId: input.root };
|
|
4493
|
+
const digest3 = head.currentKey ?? input.desiredKey;
|
|
4494
|
+
const revision = { digest: digest3, observedAt, rootId: input.root };
|
|
2834
4495
|
const published = new Set(input.publishedGuids.map((guid) => guid.toLowerCase()));
|
|
2835
4496
|
const catalog = input.nextCatalog.map((row) => {
|
|
2836
4497
|
if (!published.has(row.guid.toLowerCase())) return row;
|
|
@@ -2855,6 +4516,15 @@ async function publishImportPublication(input) {
|
|
|
2855
4516
|
return commitImportPublication(staged.candidate);
|
|
2856
4517
|
}
|
|
2857
4518
|
async function stageImportPublication(input) {
|
|
4519
|
+
const validatedArtifacts = validatePublicationArtifactClosure(input);
|
|
4520
|
+
if (!validatedArtifacts.ok) {
|
|
4521
|
+
return {
|
|
4522
|
+
ok: false,
|
|
4523
|
+
error: importPublicationFailure(validatedArtifacts.error),
|
|
4524
|
+
head: await inspectHead(input.root, input.guid, input.desiredKey)
|
|
4525
|
+
};
|
|
4526
|
+
}
|
|
4527
|
+
const artifacts = validatedArtifacts.value;
|
|
2858
4528
|
const staged = await stageSourcePackageDdc({
|
|
2859
4529
|
root: input.root,
|
|
2860
4530
|
entry: {
|
|
@@ -2862,7 +4532,7 @@ async function stageImportPublication(input) {
|
|
|
2862
4532
|
guid: input.guid,
|
|
2863
4533
|
payload: input.pack,
|
|
2864
4534
|
refs: [],
|
|
2865
|
-
artifacts
|
|
4535
|
+
artifacts,
|
|
2866
4536
|
receipt: {
|
|
2867
4537
|
guid: input.guid,
|
|
2868
4538
|
key: input.desiredKey,
|
|
@@ -2872,17 +4542,11 @@ async function stageImportPublication(input) {
|
|
|
2872
4542
|
guid: input.guid,
|
|
2873
4543
|
payload: input.pack,
|
|
2874
4544
|
refs: [],
|
|
2875
|
-
artifacts
|
|
4545
|
+
artifacts
|
|
2876
4546
|
})
|
|
2877
4547
|
}
|
|
2878
4548
|
},
|
|
2879
|
-
context:
|
|
2880
|
-
sourceMeta: "<import-publication>",
|
|
2881
|
-
anchorGuid: input.guid,
|
|
2882
|
-
affectedGuids: input.publishedGuids,
|
|
2883
|
-
producer: "source-package/import-publication",
|
|
2884
|
-
importer: "import-publication"
|
|
2885
|
-
}
|
|
4549
|
+
context: publicationContext(input)
|
|
2886
4550
|
});
|
|
2887
4551
|
if (!staged.ok) {
|
|
2888
4552
|
return {
|
|
@@ -2924,6 +4588,35 @@ async function commitImportPublication(candidate) {
|
|
|
2924
4588
|
)
|
|
2925
4589
|
};
|
|
2926
4590
|
}
|
|
4591
|
+
const transportPersisted = await persistTransport(candidate.input.transport);
|
|
4592
|
+
if (!transportPersisted) {
|
|
4593
|
+
await restoreImportPublication(candidate);
|
|
4594
|
+
return {
|
|
4595
|
+
ok: false,
|
|
4596
|
+
error: {
|
|
4597
|
+
code: "source-package-publication-invalid",
|
|
4598
|
+
expected: "the sidecar and DDC publication to commit atomically",
|
|
4599
|
+
hint: "repair the sidecar destination, then rebuild or cold-cook the source package",
|
|
4600
|
+
detail: "sidecar transport persistence failed; restored the previous DDC/LKG generation",
|
|
4601
|
+
diagnostic: sourcePackageError(
|
|
4602
|
+
"source-package-publication-invalid",
|
|
4603
|
+
{
|
|
4604
|
+
sourceMeta: "<import-publication>",
|
|
4605
|
+
anchorGuid: candidate.input.guid,
|
|
4606
|
+
affectedGuids: candidate.input.publishedGuids,
|
|
4607
|
+
producer: "source-package/import-publication",
|
|
4608
|
+
importer: "import-publication"
|
|
4609
|
+
},
|
|
4610
|
+
{ stage: "route-integrity", reason: "sidecar transport persistence failed" }
|
|
4611
|
+
)
|
|
4612
|
+
},
|
|
4613
|
+
head: await inspectHead(
|
|
4614
|
+
candidate.input.root,
|
|
4615
|
+
candidate.input.guid,
|
|
4616
|
+
candidate.input.desiredKey
|
|
4617
|
+
)
|
|
4618
|
+
};
|
|
4619
|
+
}
|
|
2927
4620
|
const projected = projectImportPublication(candidate.input, publication.value, Date.now());
|
|
2928
4621
|
return {
|
|
2929
4622
|
ok: true,
|
|
@@ -2931,7 +4624,7 @@ async function commitImportPublication(candidate) {
|
|
|
2931
4624
|
head: publication.value,
|
|
2932
4625
|
catalog: projected.catalog,
|
|
2933
4626
|
revision: projected.revision,
|
|
2934
|
-
transportPersisted
|
|
4627
|
+
transportPersisted
|
|
2935
4628
|
};
|
|
2936
4629
|
}
|
|
2937
4630
|
async function discardImportPublication(candidate) {
|
|
@@ -2941,6 +4634,6 @@ async function restoreImportPublication(candidate) {
|
|
|
2941
4634
|
await candidate.ddc.session.restoreEntry(candidate.ddc);
|
|
2942
4635
|
}
|
|
2943
4636
|
|
|
2944
|
-
export { AssetOutputProducerRegistry, DEFAULT_CATALOG_IMPORTER_KEYS, ImporterRegistry, SHADER_RESERVED_IMPORTER_KEY, buildCatalogResult, buildScriptablePack, canonicalScriptableSourcePath, catalogImporterPolicy, commitImportPublication, containsSourcePackageError, createImportProduct, createSceneAssetOutputProducer, createScriptablePackStagedAssetSnapshotSource, createStandardAssetOutputProducerRegistry, declaredPackExternalOutputs, discardImportPublication, finalizeImportProducts, finalizeSourcePackage, materialAssetOutputProducer, materializePreparedScriptablePack, meshAssetOutputProducer, normaliseForPack, normalizeSourcePackageError, packMeshBinV4, parseProducerReadiness,
|
|
4637
|
+
export { AssetOutputProducerRegistry, DEFAULT_CATALOG_IMPORTER_KEYS, ImporterRegistry, SHADER_RESERVED_IMPORTER_KEY, buildCatalogResult, buildScriptablePack, buildScriptablePackWorklist, canonicalScriptableSourcePath, catalogImporterPolicy, commitImportPublication, containsSourcePackageError, createImportProduct, createPreExternalizedSceneAssetOutputProducer, createSceneAssetOutputProducer, createScriptablePackFileAssetSnapshotSource, createScriptablePackStagedAssetSnapshotSource, createStandardAssetOutputProducerRegistry, declaredPackExternalOutputs, deriveDefaultLodScreenCoverages, discardImportPublication, finalizeImportProducts, finalizeSourcePackage, iesImporter, materialAssetOutputProducer, materializePreparedScriptablePack, meshAssetOutputProducer, normaliseForPack, normalizeSourcePackageError, packMeshBinV4, parseLm63TypeC, parseProducerReadiness, prepareDirectPackTransport, prepareLegacyPackTransport, produceBuildAssets, produceScriptablePackProducts, produceSourcePackage, projectImportProductForBuild, publishImportPublication, readCookedAuthoredPack, readFloat16LE, reconcileMeshLodMeta, resampleTypeC, restoreImportPublication, runImport, sourceDeclarationForCatalogPath, sourcePackageAssetsByGuid, sourcePackageError, stageImportPublication, textureAssetOutputProducer, validateIesProfilePayload, validateMeshLodContract };
|
|
2945
4638
|
//# sourceMappingURL=index.mjs.map
|
|
2946
4639
|
//# sourceMappingURL=index.mjs.map
|