@forgeax/engine-pack 0.1.25 → 0.1.27
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 +1 -1
- package/dist/build.d.ts +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.mjs +115 -67
- package/dist/build.mjs.map +1 -1
- package/dist/cli-asset.mjs.map +1 -1
- package/dist/evidence/material-cook.d.ts +23 -12
- package/dist/evidence/material-cook.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +116 -68
- package/dist/index.mjs.map +1 -1
- package/dist/material-cook.d.ts +1 -1
- package/dist/material-cook.d.ts.map +1 -1
- package/dist/material-cook.mjs +116 -68
- package/dist/material-cook.mjs.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/material-cook-receipt.unit.test.ts +9 -9
- package/src/__tests__/material-cook-schema.unit.test.ts +172 -21
- package/src/__tests__/material-surface-publication.unit.test.ts +12 -9
- package/src/__tests__/material-surface-wire.unit.test.ts +2 -2
- package/src/build.ts +2 -2
- package/src/evidence/material-cook.ts +164 -99
- package/src/index.ts +5 -2
- package/src/material-cook.ts +5 -2
- package/src/schema/material-cook.schema.json +249 -88
package/README.md
CHANGED
|
@@ -426,7 +426,7 @@ When `kind: 'material'`, the `payload` object carries `passes[]` + `values` (fea
|
|
|
426
426
|
| `values` | `Record<string, unknown>` | Child-owned values, including per-slot texture coordinates. |
|
|
427
427
|
| `parent` | `AssetGuid` | Optional serialized parent edge. |
|
|
428
428
|
|
|
429
|
-
**Validation** is performed by the material schema and build-time cook. The cook resolves the parent chain, validates values and pass programs, and emits a `material-cook/
|
|
429
|
+
**Validation** is performed by the material schema and build-time cook. The cook resolves the parent chain, validates values and pass programs, and emits a `material-cook/4` record, artifact, references, and receipt. The receipt keeps material, source, layout, program, pipeline, publication, and cook identities together with compiler/WASM provenance and generation counters. Runtime reports a structured missing-cook error instead of compiling a material; stale generations are recooked by the producer.
|
|
430
430
|
|
|
431
431
|
## `AssetGuid` API
|
|
432
432
|
|
package/dist/build.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { validateArtifactPath } from './artifact-path.js';
|
|
|
4
4
|
export { buildCatalogProjection, type CatalogAuthority, type CatalogBuildError, type CatalogBuildErrorCode, type CatalogBuildProjectionOptions, type CatalogBuildResult, type CatalogImporterPolicy, type CatalogProducerVisibility, catalogSourcePathFor, metaPathForGuid, } from './catalog-builder.js';
|
|
5
5
|
export { calculateCatalogDelta } from './catalog-delta.js';
|
|
6
6
|
export { type CatalogOutputDeclaration, type CatalogProducerMeta, type CookedPackageProjection, catalogProjectionFor, currentProjectionFor, findReservedAssetKindConflict, type PackageCatalogInput, projectCookedPackageEntry, projectExternalCatalogEntries, projectPackageCatalog, projectRuntimeCatalogRow, type RuntimeCatalogRowInput, } from './catalog-projection.js';
|
|
7
|
-
export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, type MaterialCookArtifact, type MaterialCookIdentityExpectation, type
|
|
7
|
+
export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, type MaterialCookArtifact, type MaterialCookIdentityExpectation, type MaterialCookProgram, type MaterialCookProgramContext, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, validateMaterialCookReceipt, } from './evidence/material-cook.js';
|
|
8
8
|
export { buildOfflineAssetEvidence, packageVerification } from './evidence/offline-evidence.js';
|
|
9
9
|
export { AssetGuid, isValidAssetGuidString, isValidPackSourceKey, PACK_SOURCE_KEY_RE, PackageId, } from './guid.js';
|
|
10
10
|
export { projectAssetRefs, projectSceneEntityRefs } from './inventory/binding.js';
|
package/dist/build.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,aAAa,EACb,cAAc,EACd,KAAK,EACL,cAAc,EACd,aAAa,EACb,SAAS,EACT,aAAa,EACb,SAAS,EACT,MAAM,EACN,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,UAAU,GACX,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,oBAAoB,EACpB,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,oBAAoB,EACpB,oBAAoB,EACpB,6BAA6B,EAC7B,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,6BAA6B,EAC7B,qBAAqB,EACrB,wBAAwB,EACxB,KAAK,sBAAsB,GAC5B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,KAAK,oBAAoB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,KAAK,oBAAoB,EACzB,KAAK,+BAA+B,EACpC,KAAK,mBAAmB,EACxB,KAAK,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
|
package/dist/build.mjs
CHANGED
|
@@ -10299,8 +10299,7 @@ var STANDARD_ROOT_MODULES = /* @__PURE__ */ new Set([
|
|
|
10299
10299
|
"forgeax::default-standard-pbr",
|
|
10300
10300
|
"forgeax::pbr-skin",
|
|
10301
10301
|
"forgeax_material::standard",
|
|
10302
|
-
"forgeax_material::pbr-skin"
|
|
10303
|
-
"forgeax::default-shadow-caster"
|
|
10302
|
+
"forgeax_material::pbr-skin"
|
|
10304
10303
|
]);
|
|
10305
10304
|
function isStandardRootModule(module) {
|
|
10306
10305
|
return STANDARD_ROOT_MODULES.has(module);
|
|
@@ -10379,7 +10378,7 @@ function serializeMaterialCookReceipt(receipt) {
|
|
|
10379
10378
|
function invalid(field, actual) {
|
|
10380
10379
|
return err({
|
|
10381
10380
|
code: "material-cook-record-invalid",
|
|
10382
|
-
expected: "a complete material-cook/
|
|
10381
|
+
expected: "a complete material-cook/4 record with layered identity and provenance",
|
|
10383
10382
|
hint: "re-cook the material and publish its record, artifact, references, and receipt together",
|
|
10384
10383
|
detail: {
|
|
10385
10384
|
field,
|
|
@@ -10440,7 +10439,7 @@ function validateIdentity(value) {
|
|
|
10440
10439
|
function validateMaterialCookReceipt(value, expected = {}) {
|
|
10441
10440
|
if (value === null || typeof value !== "object") return invalid("receipt");
|
|
10442
10441
|
const candidate = value;
|
|
10443
|
-
if (candidate.schemaVersion !== "material-cook/
|
|
10442
|
+
if (candidate.schemaVersion !== "material-cook/4")
|
|
10444
10443
|
return invalid("receipt.schemaVersion", candidate.schemaVersion);
|
|
10445
10444
|
const identityResult = validateIdentity(candidate.identity);
|
|
10446
10445
|
if (!identityResult.ok) return identityResult;
|
|
@@ -10478,7 +10477,7 @@ function validateMaterialCookReceipt(value, expected = {}) {
|
|
|
10478
10477
|
return invalid("receipt.identity.cookIdentity", identity.cookIdentity);
|
|
10479
10478
|
}
|
|
10480
10479
|
return ok({
|
|
10481
|
-
schemaVersion: "material-cook/
|
|
10480
|
+
schemaVersion: "material-cook/4",
|
|
10482
10481
|
sourceClosure: candidate.sourceClosure,
|
|
10483
10482
|
profile: candidate.profile,
|
|
10484
10483
|
compilerVersion: candidate.compilerVersion,
|
|
@@ -10492,7 +10491,7 @@ function validateMaterialCookReceipt(value, expected = {}) {
|
|
|
10492
10491
|
function validateCookedMaterialRecord(value) {
|
|
10493
10492
|
if (value === null || typeof value !== "object") return invalid("record");
|
|
10494
10493
|
const candidate = value;
|
|
10495
|
-
if (candidate.schemaVersion !== "material-cook/
|
|
10494
|
+
if (candidate.schemaVersion !== "material-cook/4")
|
|
10496
10495
|
return invalid("schemaVersion", candidate.schemaVersion);
|
|
10497
10496
|
if (typeof candidate.guid !== "string" || !candidate.guid) return invalid("guid");
|
|
10498
10497
|
if (candidate.materialGuid !== void 0 && typeof candidate.materialGuid !== "string")
|
|
@@ -10501,33 +10500,8 @@ function validateCookedMaterialRecord(value) {
|
|
|
10501
10500
|
return invalid("publicationGeneration", candidate.publicationGeneration);
|
|
10502
10501
|
if (candidate.specializationKey !== void 0 && typeof candidate.specializationKey !== "string")
|
|
10503
10502
|
return invalid("specializationKey");
|
|
10504
|
-
if (candidate
|
|
10505
|
-
|
|
10506
|
-
return invalid("variantContext");
|
|
10507
|
-
const context = candidate.variantContext;
|
|
10508
|
-
if (context.backend !== "webgpu" && context.backend !== "webgl2" && context.backend !== "wgpu-native" || context.capability !== "storage-buffer" && context.capability !== "uniform-fallback")
|
|
10509
|
-
return invalid("variantContext", candidate.variantContext);
|
|
10510
|
-
}
|
|
10511
|
-
if (candidate.variants !== void 0) {
|
|
10512
|
-
if (!Array.isArray(candidate.variants)) return invalid("variants");
|
|
10513
|
-
for (const [index, value2] of candidate.variants.entries()) {
|
|
10514
|
-
if (value2 === null || typeof value2 !== "object") return invalid(`variants[${index}]`);
|
|
10515
|
-
const variant = value2;
|
|
10516
|
-
const context = variant.context;
|
|
10517
|
-
if (context === null || typeof context !== "object")
|
|
10518
|
-
return invalid(`variants[${index}].context`);
|
|
10519
|
-
const contextRecord = context;
|
|
10520
|
-
if (contextRecord.backend !== "webgpu" && contextRecord.backend !== "webgl2" && contextRecord.backend !== "wgpu-native" || contextRecord.capability !== "storage-buffer" && contextRecord.capability !== "uniform-fallback")
|
|
10521
|
-
return invalid(`variants[${index}].context`, context);
|
|
10522
|
-
if (typeof variant.specializationKey !== "string" || variant.specializationKey.length === 0)
|
|
10523
|
-
return invalid(`variants[${index}].specializationKey`);
|
|
10524
|
-
if (variant.artifact === null || typeof variant.artifact !== "object")
|
|
10525
|
-
return invalid(`variants[${index}].artifact`);
|
|
10526
|
-
const variantArtifact = variant.artifact;
|
|
10527
|
-
if (typeof variantArtifact.mediaType !== "string" || typeof variantArtifact.path !== "string" || typeof variantArtifact.digest !== "string" || normalizeArtifactBytes(variantArtifact.bytes) === void 0)
|
|
10528
|
-
return invalid(`variants[${index}].artifact`);
|
|
10529
|
-
}
|
|
10530
|
-
}
|
|
10503
|
+
if ("artifact" in candidate || "variants" in candidate || "variantContext" in candidate)
|
|
10504
|
+
return invalid("programs", "legacy single-artifact publication");
|
|
10531
10505
|
if (candidate.artifactDigest !== void 0 && typeof candidate.artifactDigest !== "string")
|
|
10532
10506
|
return invalid("artifactDigest");
|
|
10533
10507
|
if (candidate.sourceClosure !== void 0 && (!Array.isArray(candidate.sourceClosure) || candidate.sourceClosure.some((path) => typeof path !== "string")))
|
|
@@ -10544,24 +10518,72 @@ function validateCookedMaterialRecord(value) {
|
|
|
10544
10518
|
if (candidate.resolved === null || typeof candidate.resolved !== "object")
|
|
10545
10519
|
return invalid("resolved");
|
|
10546
10520
|
if (candidate.refs === null || typeof candidate.refs !== "object") return invalid("refs");
|
|
10547
|
-
if (candidate.artifact === null || typeof candidate.artifact !== "object")
|
|
10548
|
-
return invalid("artifact");
|
|
10549
10521
|
if (candidate.receipt === null || typeof candidate.receipt !== "object")
|
|
10550
10522
|
return invalid("receipt");
|
|
10551
|
-
const artifact = candidate.artifact;
|
|
10552
|
-
if (typeof artifact.digest !== "string" || !Array.isArray(artifact.bytes) && !ArrayBuffer.isView(artifact.bytes)) {
|
|
10553
|
-
return invalid("artifact");
|
|
10554
|
-
}
|
|
10555
|
-
const receiptResult = validateMaterialCookReceipt(candidate.receipt, {
|
|
10556
|
-
artifactDigest: artifact.digest
|
|
10557
|
-
});
|
|
10558
|
-
if (!receiptResult.ok) return receiptResult;
|
|
10559
10523
|
const resolved = candidate.resolved;
|
|
10560
10524
|
if (!Array.isArray(resolved.passes)) return invalid("resolved.passes", resolved.passes);
|
|
10561
10525
|
if (!Array.isArray(resolved.parameters))
|
|
10562
10526
|
return invalid("resolved.parameters", resolved.parameters);
|
|
10563
10527
|
if (resolved.values === null || typeof resolved.values !== "object" || Array.isArray(resolved.values))
|
|
10564
10528
|
return invalid("resolved.values", resolved.values);
|
|
10529
|
+
const passes = resolved.passes;
|
|
10530
|
+
const passNames = /* @__PURE__ */ new Set();
|
|
10531
|
+
for (const [index, pass] of passes.entries()) {
|
|
10532
|
+
if (pass === null || typeof pass !== "object" || typeof pass.name !== "string" || !pass.name || passNames.has(pass.name) || pass.program === null || typeof pass.program !== "object" || typeof pass.program.module !== "string")
|
|
10533
|
+
return invalid(`resolved.passes[${index}]`);
|
|
10534
|
+
passNames.add(pass.name);
|
|
10535
|
+
}
|
|
10536
|
+
if (!Array.isArray(candidate.programs) || candidate.programs.length === 0)
|
|
10537
|
+
return invalid("programs");
|
|
10538
|
+
const programs = [];
|
|
10539
|
+
const programKeys = /* @__PURE__ */ new Set();
|
|
10540
|
+
const selections = /* @__PURE__ */ new Set();
|
|
10541
|
+
const selectedPasses = /* @__PURE__ */ new Set();
|
|
10542
|
+
for (const [index, entry] of candidate.programs.entries()) {
|
|
10543
|
+
const field = `programs[${index}]`;
|
|
10544
|
+
if (entry === null || typeof entry !== "object") return invalid(field);
|
|
10545
|
+
const program = entry;
|
|
10546
|
+
if (typeof program.specializationKey !== "string" || !program.specializationKey || programKeys.has(program.specializationKey))
|
|
10547
|
+
return invalid(`${field}.specializationKey`);
|
|
10548
|
+
programKeys.add(program.specializationKey);
|
|
10549
|
+
if (program.artifact === null || typeof program.artifact !== "object")
|
|
10550
|
+
return invalid(`${field}.artifact`);
|
|
10551
|
+
const artifact = program.artifact;
|
|
10552
|
+
const bytes = normalizeArtifactBytes(artifact.bytes);
|
|
10553
|
+
if (artifact.mediaType !== "text/wgsl" || typeof artifact.path !== "string" || !artifact.path || typeof artifact.digest !== "string" || !artifact.digest || bytes === void 0)
|
|
10554
|
+
return invalid(`${field}.artifact`);
|
|
10555
|
+
if (!Array.isArray(program.selections) || program.selections.length === 0)
|
|
10556
|
+
return invalid(`${field}.selections`);
|
|
10557
|
+
const programSelections = [];
|
|
10558
|
+
for (const [selectionIndex, selection] of program.selections.entries()) {
|
|
10559
|
+
const selectionField = `${field}.selections[${selectionIndex}]`;
|
|
10560
|
+
if (selection === null || typeof selection !== "object" || !passNames.has(selection.pass))
|
|
10561
|
+
return invalid(selectionField);
|
|
10562
|
+
const context = validateMaterialCookProgramContext(selection.context);
|
|
10563
|
+
if (!context.ok)
|
|
10564
|
+
return invalid(
|
|
10565
|
+
`${selectionField}.${context.error.detail.field}`,
|
|
10566
|
+
context.error.detail.actual
|
|
10567
|
+
);
|
|
10568
|
+
const key = JSON.stringify([selection.pass, materialProgramContextKey(context.value)]);
|
|
10569
|
+
if (selections.has(key)) return invalid(selectionField, "ambiguous Pass/context selection");
|
|
10570
|
+
selections.add(key);
|
|
10571
|
+
selectedPasses.add(selection.pass);
|
|
10572
|
+
programSelections.push({ pass: selection.pass, context: context.value });
|
|
10573
|
+
}
|
|
10574
|
+
programs.push({
|
|
10575
|
+
specializationKey: program.specializationKey,
|
|
10576
|
+
artifact: { mediaType: "text/wgsl", path: artifact.path, digest: artifact.digest, bytes },
|
|
10577
|
+
selections: programSelections
|
|
10578
|
+
});
|
|
10579
|
+
}
|
|
10580
|
+
if ([...passNames].some((pass) => !selectedPasses.has(pass)))
|
|
10581
|
+
return invalid("programs.selections", "unpublished Pass");
|
|
10582
|
+
const manifestDigest = createMaterialProgramSetDigest(programs, passes);
|
|
10583
|
+
const receiptResult = validateMaterialCookReceipt(candidate.receipt, {
|
|
10584
|
+
artifactDigest: manifestDigest
|
|
10585
|
+
});
|
|
10586
|
+
if (!receiptResult.ok) return receiptResult;
|
|
10565
10587
|
let expectedLayerPlanIdentity;
|
|
10566
10588
|
try {
|
|
10567
10589
|
expectedLayerPlanIdentity = materialLayerPlanIdentity({
|
|
@@ -10576,44 +10598,70 @@ function validateCookedMaterialRecord(value) {
|
|
|
10576
10598
|
receiptResult.value.derivedInterface.layerPlanIdentity
|
|
10577
10599
|
);
|
|
10578
10600
|
}
|
|
10579
|
-
if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !==
|
|
10601
|
+
if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !== manifestDigest)
|
|
10580
10602
|
return invalid("artifactDigest", candidate.artifactDigest);
|
|
10581
10603
|
if (candidate.publicationGeneration !== void 0 && receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration)
|
|
10582
10604
|
return invalid("receipt.identity.cookGeneration", receiptResult.value.identity.cookGeneration);
|
|
10583
|
-
|
|
10605
|
+
return ok({
|
|
10584
10606
|
...candidate,
|
|
10585
|
-
|
|
10586
|
-
...artifact,
|
|
10587
|
-
bytes: normalizeArtifactBytes(artifact.bytes)
|
|
10588
|
-
},
|
|
10589
|
-
...Array.isArray(candidate.variants) ? {
|
|
10590
|
-
variants: candidate.variants.map((value2) => {
|
|
10591
|
-
const variant = value2;
|
|
10592
|
-
const variantArtifact = variant.artifact;
|
|
10593
|
-
return {
|
|
10594
|
-
...variant,
|
|
10595
|
-
artifact: {
|
|
10596
|
-
...variantArtifact,
|
|
10597
|
-
bytes: normalizeArtifactBytes(variantArtifact.bytes)
|
|
10598
|
-
}
|
|
10599
|
-
};
|
|
10600
|
-
})
|
|
10601
|
-
} : {},
|
|
10607
|
+
programs,
|
|
10602
10608
|
receipt: receiptResult.value
|
|
10603
|
-
};
|
|
10604
|
-
return ok(normalized);
|
|
10609
|
+
});
|
|
10605
10610
|
}
|
|
10606
10611
|
function projectCookedMaterialRecord(record2) {
|
|
10607
10612
|
return {
|
|
10608
10613
|
resolved: record2.resolved,
|
|
10609
10614
|
refs: record2.refs,
|
|
10610
|
-
|
|
10611
|
-
...record2.variantContext === void 0 ? {} : { variantContext: record2.variantContext },
|
|
10612
|
-
...record2.variants === void 0 ? {} : { variants: record2.variants },
|
|
10615
|
+
programs: record2.programs,
|
|
10613
10616
|
receipt: record2.receipt,
|
|
10614
10617
|
schemaVersion: record2.schemaVersion
|
|
10615
10618
|
};
|
|
10616
10619
|
}
|
|
10620
|
+
function materialProgramContextKey(context) {
|
|
10621
|
+
return JSON.stringify(jsonValue(context));
|
|
10622
|
+
}
|
|
10623
|
+
function validateMaterialCookProgramContext(value) {
|
|
10624
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
10625
|
+
return invalid("context", value);
|
|
10626
|
+
const context = value;
|
|
10627
|
+
const fields = {
|
|
10628
|
+
backend: ["webgpu", "webgl2", "wgpu-native"],
|
|
10629
|
+
capability: ["storage-buffer", "uniform-fallback"],
|
|
10630
|
+
pipeline: ["forward", "deferred"],
|
|
10631
|
+
geometry: ["mesh", "skinned", "sprite"],
|
|
10632
|
+
pass: ["forward", "shadow", "depth"],
|
|
10633
|
+
profile: ["forgeax-material-wgsl-v1"],
|
|
10634
|
+
toolchain: ["naga-oil"],
|
|
10635
|
+
instrumentation: ["none", "validation"]
|
|
10636
|
+
};
|
|
10637
|
+
for (const field of Object.keys(context)) {
|
|
10638
|
+
if (!(field in fields)) return invalid(`context.${field}`, context[field]);
|
|
10639
|
+
}
|
|
10640
|
+
for (const [field, allowed] of Object.entries(fields)) {
|
|
10641
|
+
if (!allowed.includes(context[field]))
|
|
10642
|
+
return invalid(`context.${field}`, context[field]);
|
|
10643
|
+
}
|
|
10644
|
+
return ok({ ...context });
|
|
10645
|
+
}
|
|
10646
|
+
function createMaterialProgramSetDigest(programs, passes) {
|
|
10647
|
+
const manifest = {
|
|
10648
|
+
passes,
|
|
10649
|
+
programs: programs.map((program) => ({
|
|
10650
|
+
specializationKey: program.specializationKey,
|
|
10651
|
+
artifact: {
|
|
10652
|
+
path: program.artifact.path,
|
|
10653
|
+
mediaType: program.artifact.mediaType,
|
|
10654
|
+
digest: program.artifact.digest
|
|
10655
|
+
},
|
|
10656
|
+
selections: [...program.selections].sort(
|
|
10657
|
+
(a, b) => JSON.stringify(jsonValue(a)).localeCompare(JSON.stringify(jsonValue(b)))
|
|
10658
|
+
)
|
|
10659
|
+
})).sort((a, b) => a.specializationKey.localeCompare(b.specializationKey))
|
|
10660
|
+
};
|
|
10661
|
+
return createMaterialArtifactDigest(
|
|
10662
|
+
new TextEncoder().encode(JSON.stringify(jsonValue(manifest)))
|
|
10663
|
+
);
|
|
10664
|
+
}
|
|
10617
10665
|
function packageEvidence(input) {
|
|
10618
10666
|
return {
|
|
10619
10667
|
guid: input.guid,
|