@plasius/asset-contracts 0.7.0 → 0.8.0

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/dist/index.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  SHADER_VALIDATION_EVIDENCE_VERSION,
6
6
  SUPPORTED_ADDITIVE_WEBGPU_MATRIX_POLICIES,
7
7
  SUPPORTED_STABLE_WEBGPU_MATRIX_POLICIES,
8
- canonicalizeGpuContract as canonicalizeGpuContract3,
9
- computeSha256 as computeSha2562,
8
+ canonicalizeGpuContract as canonicalizeGpuContract4,
9
+ computeSha256 as computeSha2563,
10
10
  parseGpuInterfaceManifest,
11
11
  parseJsonBytes,
12
12
  parseModelGpuCompatibilityDescriptor,
@@ -2797,7 +2797,7 @@ function requireEnum(value, allowed, fieldName) {
2797
2797
  }
2798
2798
  function requireReasonCodes(value, fieldName) {
2799
2799
  const entries = asDenseArray(value, fieldName, 0, 32);
2800
- const result = entries.map((entry, index) => requireReasonCode(entry, `${fieldName}[${index}]`));
2800
+ const result = entries.map((entry2, index) => requireReasonCode(entry2, `${fieldName}[${index}]`));
2801
2801
  if (new Set(result).size !== result.length) throw new Error(`${fieldName} must not contain duplicates.`);
2802
2802
  return result;
2803
2803
  }
@@ -3119,7 +3119,7 @@ function createPvoxRuntimeRequestProfileV1(value) {
3119
3119
  const record2 = asRecord(value, fieldName);
3120
3120
  exactKeys(record2, ["profileId", "fidelityProfileId", "capabilityProfileId", "geometryMode", "requiredCapabilities", "limits"], fieldName);
3121
3121
  const requestedCapabilityEntries = asDenseArray(record2.requiredCapabilities, `${fieldName}.requiredCapabilities`, 1, PVOX_CAPABILITIES.length);
3122
- const requiredCapabilities = requestedCapabilityEntries.map((entry, index) => requireEnum(entry, PVOX_CAPABILITIES, `${fieldName}.requiredCapabilities[${index}]`));
3122
+ const requiredCapabilities = requestedCapabilityEntries.map((entry2, index) => requireEnum(entry2, PVOX_CAPABILITIES, `${fieldName}.requiredCapabilities[${index}]`));
3123
3123
  if (new Set(requiredCapabilities).size !== requiredCapabilities.length) {
3124
3124
  throw new Error(`${fieldName}.requiredCapabilities must not contain duplicates.`);
3125
3125
  }
@@ -3282,7 +3282,7 @@ function createPvoxAssetManifestV1(input) {
3282
3282
  }
3283
3283
  if (expectedOffset !== artifact.byteLength) throw new Error("PvoxAssetManifestV1 pages must exactly cover the artifact bytes.");
3284
3284
  const lodEntries = asDenseArray(record2.lods, "PvoxAssetManifestV1.lods", 1, 4);
3285
- const lods = lodEntries.map((entry, index) => createLod(entry, index, pages.length));
3285
+ const lods = lodEntries.map((entry2, index) => createLod(entry2, index, pages.length));
3286
3286
  for (const [index, current] of lods.entries()) {
3287
3287
  if (current.level !== index) throw new Error("PvoxAssetManifestV1 LOD levels must be contiguous from LOD0.");
3288
3288
  const previous = lods[index - 1];
@@ -3518,7 +3518,7 @@ function createPhysicalPropertyEvidence(input) {
3518
3518
  const reviewedBy = record2.reviewedBy === void 0 ? void 0 : requireToken(record2.reviewedBy, "PhysicalPropertyEvidence.reviewedBy");
3519
3519
  const reviewedAt = record2.reviewedAt === void 0 ? void 0 : requireTimestamp(record2.reviewedAt, "PhysicalPropertyEvidence.reviewedAt");
3520
3520
  const reviewToken = record2.reviewToken === void 0 ? void 0 : requireAttestation(record2.reviewToken, "PhysicalPropertyEvidence.reviewToken");
3521
- if (new Set([reviewedBy, reviewedAt, reviewToken].map((entry) => entry === void 0)).size !== 1) throw new Error("PhysicalPropertyEvidence signed review identity, timestamp, and token must be supplied together.");
3521
+ if (new Set([reviewedBy, reviewedAt, reviewToken].map((entry2) => entry2 === void 0)).size !== 1) throw new Error("PhysicalPropertyEvidence signed review identity, timestamp, and token must be supplied together.");
3522
3522
  if (provenance === "inferred" && reviewedBy === void 0) throw new Error("Inferred PhysicalPropertyEvidence requires human review.");
3523
3523
  return deepFreeze2({
3524
3524
  property,
@@ -3541,9 +3541,9 @@ function createPvoxPhysicalRegionInventoryV1(input) {
3541
3541
  exactKeys(record2, ["inventoryVersion", "subjectContentHash", "inventoryHash", "inventoryHashAttestation", "validationEvidenceHash", "entries"], fieldName);
3542
3542
  if (record2.inventoryVersion !== PVOX_PHYSICAL_REGION_INVENTORY_VERSION) throw new Error(`${fieldName}.inventoryVersion is unsupported.`);
3543
3543
  const entriesInput = asDenseArray(record2.entries, `${fieldName}.entries`, 1, PVOX_DEFAULT_LIMITS.maximumMaterialRegions);
3544
- const entries = entriesInput.map((entry, index) => {
3544
+ const entries = entriesInput.map((entry2, index) => {
3545
3545
  const entryName = `${fieldName}.entries[${index}]`;
3546
- const item = asRecord(entry, entryName);
3546
+ const item = asRecord(entry2, entryName);
3547
3547
  exactKeys(item, ["regionIndex", "physicalPaletteIndex", "regionId", "materialId"], entryName);
3548
3548
  return {
3549
3549
  regionIndex: requireInteger(item.regionIndex, `${entryName}.regionIndex`, 0, PVOX_DEFAULT_LIMITS.maximumMaterialRegions - 1),
@@ -3552,7 +3552,7 @@ function createPvoxPhysicalRegionInventoryV1(input) {
3552
3552
  materialId: requireToken(item.materialId, `${entryName}.materialId`)
3553
3553
  };
3554
3554
  });
3555
- if (entries.some((entry, index) => entry.regionIndex !== index)) throw new Error(`${fieldName} regionIndex values must be contiguous and canonically ordered.`);
3555
+ if (entries.some((entry2, index) => entry2.regionIndex !== index)) throw new Error(`${fieldName} regionIndex values must be contiguous and canonically ordered.`);
3556
3556
  const pairs = entries.map(({ regionId, materialId }) => `${regionId}\0${materialId}`);
3557
3557
  if (new Set(pairs).size !== pairs.length) throw new Error(`${fieldName} region/material pairs must be unique.`);
3558
3558
  const inventoryHash = requireSha256(record2.inventoryHash, `${fieldName}.inventoryHash`);
@@ -3689,9 +3689,9 @@ function createPvoxEditJournalCurrentState(input, baseManifest) {
3689
3689
  const record2 = asRecord(input, fieldName);
3690
3690
  exactKeys(record2, ["baseContentHash", "basePageSetHash", "placementId", "gridVersion", "revision", "rootHash", "latestJournalHash", "pageHashes"], fieldName);
3691
3691
  const pageEntries = asDenseArray(record2.pageHashes, `${fieldName}.pageHashes`, baseManifest.pages.length, baseManifest.pages.length);
3692
- const pageHashes = pageEntries.map((entry, index) => {
3692
+ const pageHashes = pageEntries.map((entry2, index) => {
3693
3693
  const entryName = `${fieldName}.pageHashes[${index}]`;
3694
- const page = asRecord(entry, entryName);
3694
+ const page = asRecord(entry2, entryName);
3695
3695
  exactKeys(page, ["pageIndex", "sha256"], entryName);
3696
3696
  const pageIndex = requireInteger(page.pageIndex, `${entryName}.pageIndex`, 0, baseManifest.pages.length - 1);
3697
3697
  if (pageIndex !== index) throw new Error(`${fieldName}.pageHashes must be complete and ordered by pageIndex.`);
@@ -3742,9 +3742,9 @@ function createPvoxEditJournal(input, baseManifestInput, currentStateInput) {
3742
3742
  }
3743
3743
  }
3744
3744
  const patchEntries = asDenseArray(record2.patches, "PvoxEditJournal.patches", 1, PVOX_MAX_EDIT_PATCHES);
3745
- const patches = patchEntries.map((entry, index) => {
3745
+ const patches = patchEntries.map((entry2, index) => {
3746
3746
  const fieldName = `PvoxEditJournal.patches[${index}]`;
3747
- const patch = asRecord(entry, fieldName);
3747
+ const patch = asRecord(entry2, fieldName);
3748
3748
  exactKeys(patch, ["fieldKind", "lodLevel", "partitionIndex", "hierarchyDepth", "mortonCode", "expectedPageIndex", "expectedPageHash", "operation", "expectedBrickHash", "resultingBrickHash", "resultingPageHash"], fieldName);
3749
3749
  const mortonCode = requireString(patch.mortonCode, `${fieldName}.mortonCode`, 16);
3750
3750
  if (!MORTON_CODE.test(mortonCode)) throw new Error(`${fieldName}.mortonCode must be a canonical Morton code.`);
@@ -3821,7 +3821,7 @@ function createPvoxEditJournalChain(input, baseManifestInput) {
3821
3821
  const journals = [];
3822
3822
  const operationIds = /* @__PURE__ */ new Set();
3823
3823
  const currentPageHashes = new Map(baseManifest.pages.map(({ pageIndex, sha256: sha2562 }) => [pageIndex, sha2562]));
3824
- for (const entry of entries) {
3824
+ for (const entry2 of entries) {
3825
3825
  const previous = journals.at(-1);
3826
3826
  const currentState = previous === void 0 ? void 0 : {
3827
3827
  baseContentHash: previous.baseContentHash,
@@ -3833,7 +3833,7 @@ function createPvoxEditJournalChain(input, baseManifestInput) {
3833
3833
  latestJournalHash: previous.journalHash,
3834
3834
  pageHashes: baseManifest.pages.map(({ pageIndex }) => ({ pageIndex, sha256: currentPageHashes.get(pageIndex) }))
3835
3835
  };
3836
- const journal = createPvoxEditJournal(entry, baseManifest, currentState);
3836
+ const journal = createPvoxEditJournal(entry2, baseManifest, currentState);
3837
3837
  if (previous === void 0 && (journal.expectedRevision !== 0 || journal.previousJournalHash !== PVOX_EDIT_JOURNAL_GENESIS_HASH)) {
3838
3838
  throw new Error("PvoxEditJournalChain must begin at the canonical genesis revision.");
3839
3839
  }
@@ -3891,10 +3891,10 @@ function createTransform2(value, fieldName) {
3891
3891
  exactKeys(record2, ["translationMetres", "rotationQuaternion", "scale"], fieldName);
3892
3892
  const translationMetres = requireVector(record2.translationMetres, `${fieldName}.translationMetres`);
3893
3893
  const rotationEntries = asDenseArray(record2.rotationQuaternion, `${fieldName}.rotationQuaternion`, 4, 4);
3894
- const rotationQuaternion = rotationEntries.map((entry, index) => requireNumber(entry, `${fieldName}.rotationQuaternion[${index}]`, -1, 1));
3894
+ const rotationQuaternion = rotationEntries.map((entry2, index) => requireNumber(entry2, `${fieldName}.rotationQuaternion[${index}]`, -1, 1));
3895
3895
  if (Math.abs(Math.hypot(...rotationQuaternion) - 1) > 1e-4) throw new Error(`${fieldName}.rotationQuaternion must be normalized.`);
3896
3896
  const scale = requireVector(record2.scale, `${fieldName}.scale`);
3897
- if (scale.some((entry) => entry <= 0)) throw new Error(`${fieldName}.scale values must be positive.`);
3897
+ if (scale.some((entry2) => entry2 <= 0)) throw new Error(`${fieldName}.scale values must be positive.`);
3898
3898
  return { translationMetres, rotationQuaternion, scale };
3899
3899
  }
3900
3900
  function createAssemblyChild2(value, index, resolutionId, candidateId) {
@@ -4062,10 +4062,10 @@ function createModelProcessingManifestV2(input) {
4062
4062
  }
4063
4063
  const capabilityEntries = asDenseArray(record2.capabilities, "ModelProcessingManifestV2.capabilities", PVOX_CAPABILITIES.length, PVOX_CAPABILITIES.length);
4064
4064
  const capabilities = capabilityEntries.map(createVoxelCapabilityAssessment);
4065
- const byCapability = new Map(capabilities.map((entry) => [entry.capability, entry]));
4065
+ const byCapability = new Map(capabilities.map((entry2) => [entry2.capability, entry2]));
4066
4066
  if (byCapability.size !== PVOX_CAPABILITIES.length || PVOX_CAPABILITIES.some((name) => !byCapability.has(name))) throw new Error("ModelProcessingManifestV2 must include every PVOX capability exactly once.");
4067
4067
  const orderedCapabilities = PVOX_CAPABILITIES.map((name) => byCapability.get(name));
4068
- if (orderedCapabilities.some((entry) => entry.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 capability evidence must bind the binaryClosureHash.");
4068
+ if (orderedCapabilities.some((entry2) => entry2.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 capability evidence must bind the binaryClosureHash.");
4069
4069
  const capabilityEvidenceSetHash = requireSha256(record2.capabilityEvidenceSetHash, "ModelProcessingManifestV2.capabilityEvidenceSetHash");
4070
4070
  const capabilityEvidenceSetAttestation = createHashAttestation(
4071
4071
  record2.capabilityEvidenceSetAttestation,
@@ -4074,7 +4074,7 @@ function createModelProcessingManifestV2(input) {
4074
4074
  "ModelProcessingManifestV2.capabilityEvidenceSetAttestation"
4075
4075
  );
4076
4076
  const requiredCapabilityEntries = asDenseArray(record2.requiredCapabilities, "ModelProcessingManifestV2.requiredCapabilities", 1, PVOX_CAPABILITIES.length);
4077
- const requiredCapabilities = requiredCapabilityEntries.map((entry, index) => requireEnum(entry, PVOX_CAPABILITIES, `ModelProcessingManifestV2.requiredCapabilities[${index}]`));
4077
+ const requiredCapabilities = requiredCapabilityEntries.map((entry2, index) => requireEnum(entry2, PVOX_CAPABILITIES, `ModelProcessingManifestV2.requiredCapabilities[${index}]`));
4078
4078
  if (new Set(requiredCapabilities).size !== requiredCapabilities.length) throw new Error("ModelProcessingManifestV2.requiredCapabilities must be unique.");
4079
4079
  if (!requiredCapabilities.includes("rendering")) throw new Error("ModelProcessingManifestV2 rendering capability is always required.");
4080
4080
  if (technicalProfile.hasCollision !== (byCapability.get("collision")?.status === "supported")) throw new Error("ModelProcessingManifestV2 collision capability must match technicalProfile.hasCollision.");
@@ -4087,9 +4087,9 @@ function createModelProcessingManifestV2(input) {
4087
4087
  }
4088
4088
  const physicalEntries = asDenseArray(record2.physicalProperties, "ModelProcessingManifestV2.physicalProperties", 0, PVOX_DEFAULT_LIMITS.maximumPhysicalEvidenceEntries);
4089
4089
  const physicalProperties = physicalEntries.map(createPhysicalPropertyEvidence);
4090
- const byRegionProperty = new Map(physicalProperties.map((entry) => [`${entry.regionId}\0${entry.materialId}\0${entry.property}`, entry]));
4090
+ const byRegionProperty = new Map(physicalProperties.map((entry2) => [`${entry2.regionId}\0${entry2.materialId}\0${entry2.property}`, entry2]));
4091
4091
  if (byRegionProperty.size !== physicalProperties.length) throw new Error("ModelProcessingManifestV2 physical properties must be unique per region, material, and property.");
4092
- if (physicalProperties.some((entry) => entry.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 physical evidence must bind the PVOX binary closure subject.");
4092
+ if (physicalProperties.some((entry2) => entry2.subjectContentHash !== binaryClosureHash)) throw new Error("ModelProcessingManifestV2 physical evidence must bind the PVOX binary closure subject.");
4093
4093
  const authoritativePairs = physicalRegionInventory.entries.map(({ regionId, materialId }) => `${regionId}\0${materialId}`);
4094
4094
  const authoritativePairSet = new Set(authoritativePairs);
4095
4095
  if (physicalProperties.some(({ regionId, materialId }) => !authoritativePairSet.has(`${regionId}\0${materialId}`))) {
@@ -4171,7 +4171,7 @@ function createModelProcessingManifestV2(input) {
4171
4171
  throw new Error("ModelProcessingManifestV2 fidelity evidence must exactly match every governed PVOX LOD0 metric.");
4172
4172
  }
4173
4173
  const childEntries = asDenseArray(record2.children, "ModelProcessingManifestV2.children", 0, PVOX_DEFAULT_LIMITS.maximumAssemblyChildren);
4174
- const children = childEntries.map((entry, index) => createAssemblyChild2(entry, index, resolutionId, candidateId));
4174
+ const children = childEntries.map((entry2, index) => createAssemblyChild2(entry2, index, resolutionId, candidateId));
4175
4175
  const kind = requireEnum(record2.kind, ["leaf", "assembly"], "ModelProcessingManifestV2.kind");
4176
4176
  if (kind === "leaf" && children.length !== 0) throw new Error("A leaf ModelProcessingManifestV2 cannot contain children.");
4177
4177
  if (kind === "leaf" && technicalProfile.partitionCount !== 1) throw new Error("A leaf ModelProcessingManifestV2 must have one partition.");
@@ -4254,9 +4254,9 @@ function createCandidateAssetRef2(value) {
4254
4254
  }
4255
4255
  function createViews(value, resolutionId, candidateId) {
4256
4256
  const entries = asDenseArray(value, "ModelCandidateV2.views", 4, 4);
4257
- const parsed = entries.map((entry, index) => {
4257
+ const parsed = entries.map((entry2, index) => {
4258
4258
  const fieldName = `ModelCandidateV2.views[${index}]`;
4259
- const record2 = asRecord(entry, fieldName);
4259
+ const record2 = asRecord(entry2, fieldName);
4260
4260
  exactKeys(record2, ["kind", "imageUri", "sha256", "contentType", "width", "height"], fieldName);
4261
4261
  const kind = requireEnum(record2.kind, MODEL_CONFIRMATION_VIEW_KINDS, `${fieldName}.kind`);
4262
4262
  const expectedUri = `mcp://models/resolutions/${resolutionId}/candidates/${candidateId}/${kind}.png`;
@@ -4264,7 +4264,7 @@ function createViews(value, resolutionId, candidateId) {
4264
4264
  if (record2.contentType !== "image/png" || record2.width !== MODEL_CONFIRMATION_VIEW_SIZE_PX || record2.height !== MODEL_CONFIRMATION_VIEW_SIZE_PX) throw new Error(`${fieldName} must be an authenticated 1024x1024 PNG.`);
4265
4265
  return { kind, imageUri: expectedUri, sha256: requireSha256(record2.sha256, `${fieldName}.sha256`), contentType: "image/png", width: MODEL_CONFIRMATION_VIEW_SIZE_PX, height: MODEL_CONFIRMATION_VIEW_SIZE_PX };
4266
4266
  });
4267
- if (parsed.some((entry, index) => entry.kind !== MODEL_CONFIRMATION_VIEW_KINDS[index])) throw new Error("ModelCandidateV2.views must be ordered front, left, top, isometric.");
4267
+ if (parsed.some((entry2, index) => entry2.kind !== MODEL_CONFIRMATION_VIEW_KINDS[index])) throw new Error("ModelCandidateV2.views must be ordered front, left, top, isometric.");
4268
4268
  return parsed;
4269
4269
  }
4270
4270
  function createRenderEvidence2(value) {
@@ -4463,7 +4463,7 @@ function createModelCandidateV2(input) {
4463
4463
  );
4464
4464
  const gateEntries = asDenseArray(record2.hardGates, "ModelCandidateV2.hardGates", PVOX_NON_OVERRIDABLE_GATE_KINDS.length, PVOX_NON_OVERRIDABLE_GATE_KINDS.length);
4465
4465
  const gates = gateEntries.map(createPvoxGateEvidence);
4466
- const byGate = new Map(gates.map((entry) => [entry.kind, entry]));
4466
+ const byGate = new Map(gates.map((entry2) => [entry2.kind, entry2]));
4467
4467
  if (byGate.size !== PVOX_NON_OVERRIDABLE_GATE_KINDS.length || PVOX_NON_OVERRIDABLE_GATE_KINDS.some((kind) => !byGate.has(kind))) throw new Error("ModelCandidateV2 must contain every non-overridable hard gate exactly once.");
4468
4468
  const orderedGates = PVOX_NON_OVERRIDABLE_GATE_KINDS.map((kind) => byGate.get(kind));
4469
4469
  const concreteGateHashes = {
@@ -4486,7 +4486,7 @@ function createModelCandidateV2(input) {
4486
4486
  ...!match.hardConstraintPass ? ["semantic-hard-constraints-failed"] : [],
4487
4487
  ...!["allowed", "attribution-required"].includes(rights.status) ? [`rights:${rights.status}`] : [],
4488
4488
  ...processingManifest.requiredCapabilities.flatMap((capability) => {
4489
- const evidence = processingManifest.capabilities.find((entry) => entry.capability === capability);
4489
+ const evidence = processingManifest.capabilities.find((entry2) => entry2.capability === capability);
4490
4490
  return evidence.status === "supported" ? [] : [`capability:${capability}:${evidence.status}`];
4491
4491
  }),
4492
4492
  ...orderedGates.flatMap((gate) => gate.outcome === "passed" ? [] : gate.reasonCodes.map((reason) => `${gate.kind}:${reason}`))
@@ -4514,7 +4514,7 @@ function createModelCandidateV2(input) {
4514
4514
  if (record2.confirmationRequired !== false) throw new Error("Diagnostic ModelCandidateV2 confirmationRequired must be false.");
4515
4515
  if (record2.blockingReasonCodes !== void 0) {
4516
4516
  const suppliedEntries = asDenseArray(record2.blockingReasonCodes, "ModelCandidateV2.blockingReasonCodes", 1, 256);
4517
- const suppliedBlockingReasons = suppliedEntries.map((entry, index) => requireReasonCode(entry, `ModelCandidateV2.blockingReasonCodes[${index}]`));
4517
+ const suppliedBlockingReasons = suppliedEntries.map((entry2, index) => requireReasonCode(entry2, `ModelCandidateV2.blockingReasonCodes[${index}]`));
4518
4518
  if (JSON.stringify(suppliedBlockingReasons) !== JSON.stringify(blockingReasonCodes)) throw new Error("Diagnostic ModelCandidateV2 blockingReasonCodes must be derived from its evidence.");
4519
4519
  }
4520
4520
  return deepFreeze2({ ...common, admissionStatus: "diagnostic", blockingReasonCodes, confirmationRequired: false });
@@ -4568,7 +4568,7 @@ function createModelCandidateV2(input) {
4568
4568
  });
4569
4569
  }
4570
4570
  function isModelCandidateV2Confirmable(candidate) {
4571
- return candidate.admissionStatus === "confirmable" && candidate.confirmationRequired && candidate.match.hardConstraintPass && candidate.match.assurance !== "none" && (candidate.rights.status === "allowed" || candidate.rights.status === "attribution-required") && candidate.processingManifest.fidelity.outcome === "passed" && candidate.hardGates.length === PVOX_NON_OVERRIDABLE_GATE_KINDS.length && candidate.hardGates.every(({ outcome }) => outcome === "passed") && candidate.processingManifest.requiredCapabilities.every((name) => candidate.processingManifest.capabilities.find((entry) => entry.capability === name)?.status === "supported");
4571
+ return candidate.admissionStatus === "confirmable" && candidate.confirmationRequired && candidate.match.hardConstraintPass && candidate.match.assurance !== "none" && (candidate.rights.status === "allowed" || candidate.rights.status === "attribution-required") && candidate.processingManifest.fidelity.outcome === "passed" && candidate.hardGates.length === PVOX_NON_OVERRIDABLE_GATE_KINDS.length && candidate.hardGates.every(({ outcome }) => outcome === "passed") && candidate.processingManifest.requiredCapabilities.every((name) => candidate.processingManifest.capabilities.find((entry2) => entry2.capability === name)?.status === "supported");
4572
4572
  }
4573
4573
  function createModelCandidateConfirmationV2(input, expectedCandidate, expectedResolutionId) {
4574
4574
  const record2 = asRecord(input, "ModelCandidateConfirmationV2");
@@ -4665,7 +4665,7 @@ function createModelPromotionReceiptV2(input, resolutionId, candidate, confirmat
4665
4665
  const candidateAssetRef = createCandidateAssetRef2(record2.candidateAssetRef);
4666
4666
  if (JSON.stringify(candidateAssetRef) !== JSON.stringify(candidate.assetRef)) throw new Error("ModelPromotionReceiptV2 must bind the exact proposed candidate identity.");
4667
4667
  const childClosureEntries = asDenseArray(record2.assemblyChildClosureHashes, "ModelPromotionReceiptV2.assemblyChildClosureHashes", 0, PVOX_DEFAULT_LIMITS.maximumAssemblyChildren);
4668
- const assemblyChildClosureHashes = childClosureEntries.map((entry, index) => requireSha256(entry, `ModelPromotionReceiptV2.assemblyChildClosureHashes[${index}]`));
4668
+ const assemblyChildClosureHashes = childClosureEntries.map((entry2, index) => requireSha256(entry2, `ModelPromotionReceiptV2.assemblyChildClosureHashes[${index}]`));
4669
4669
  const expectedChildClosureHashes = candidate.processingManifest.children.map(({ assetRef }) => assetRef.binaryClosureHash);
4670
4670
  if (JSON.stringify(assemblyChildClosureHashes) !== JSON.stringify(expectedChildClosureHashes)) throw new Error("ModelPromotionReceiptV2 child closure sequence must match the canonical assembly order.");
4671
4671
  assertDataOnlyTree(record2.finalAssetRef, "ModelPromotionReceiptV2.finalAssetRef");
@@ -4926,12 +4926,12 @@ function copyPvoxByteInput(value, fieldName, maximumByteLength) {
4926
4926
  if (!(value instanceof Uint8Array)) throw new Error(`${fieldName} must be a Uint8Array.`);
4927
4927
  let byteLength;
4928
4928
  try {
4929
- const typedArrayPrototype2 = Object.getPrototypeOf(Uint8Array.prototype);
4930
- const byteLengthGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "byteLength")?.get;
4931
- const bufferGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "buffer")?.get;
4932
- if (byteLengthGetter2 === void 0 || bufferGetter2 === void 0) throw new Error("Typed-array intrinsics are unavailable.");
4933
- byteLength = byteLengthGetter2.call(value);
4934
- const buffer = bufferGetter2.call(value);
4929
+ const typedArrayPrototype3 = Object.getPrototypeOf(Uint8Array.prototype);
4930
+ const byteLengthGetter3 = Object.getOwnPropertyDescriptor(typedArrayPrototype3, "byteLength")?.get;
4931
+ const bufferGetter3 = Object.getOwnPropertyDescriptor(typedArrayPrototype3, "buffer")?.get;
4932
+ if (byteLengthGetter3 === void 0 || bufferGetter3 === void 0) throw new Error("Typed-array intrinsics are unavailable.");
4933
+ byteLength = byteLengthGetter3.call(value);
4934
+ const buffer = bufferGetter3.call(value);
4935
4935
  if (typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer) {
4936
4936
  throw new Error(`${fieldName} must not use shared mutable storage.`);
4937
4937
  }
@@ -6701,9 +6701,9 @@ function snapshot(value, budget, depth = 0) {
6701
6701
  return value;
6702
6702
  }
6703
6703
  if (Array.isArray(value)) return Object.freeze(list(value).map((item) => snapshot(item, budget, depth + 1)));
6704
- const fields3 = record(value);
6705
- for (const key of Object.keys(fields3)) fields3[key] = snapshot(fields3[key], budget, depth + 1);
6706
- return Object.freeze(fields3);
6704
+ const fields4 = record(value);
6705
+ for (const key of Object.keys(fields4)) fields4[key] = snapshot(fields4[key], budget, depth + 1);
6706
+ return Object.freeze(fields4);
6707
6707
  }
6708
6708
  function path(value) {
6709
6709
  if (typeof value !== "string" || value.length > 1024 || !value.length) fail();
@@ -6775,14 +6775,14 @@ async function qualify(input) {
6775
6775
  contentType(file.contentType);
6776
6776
  }
6777
6777
  const entries = list(inventory.entries).map(record);
6778
- uniquePaths(entries.map((entry) => path(entry.path)));
6778
+ uniquePaths(entries.map((entry2) => path(entry2.path)));
6779
6779
  const ids = /* @__PURE__ */ new Set();
6780
- for (const entry of entries) {
6781
- if (Object.keys(entry).some((key) => !["id", "path", "role", "contentType"].includes(key)) || typeof entry.id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(entry.id) || ids.has(entry.id) || !["mesh", "material", "texture", "animation", "auxiliary"].includes(entry.role)) fail();
6782
- ids.add(entry.id);
6783
- const descriptor = descriptors.get(entry.path);
6780
+ for (const entry2 of entries) {
6781
+ if (Object.keys(entry2).some((key) => !["id", "path", "role", "contentType"].includes(key)) || typeof entry2.id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(entry2.id) || ids.has(entry2.id) || !["mesh", "material", "texture", "animation", "auxiliary"].includes(entry2.role)) fail();
6782
+ ids.add(entry2.id);
6783
+ const descriptor = descriptors.get(entry2.path);
6784
6784
  if (!descriptor) fail("inventory-mismatch");
6785
- if (entry.contentType !== void 0 && contentType(entry.contentType) !== descriptor.contentType) fail("content-mismatch");
6785
+ if (entry2.contentType !== void 0 && contentType(entry2.contentType) !== descriptor.contentType) fail("content-mismatch");
6786
6786
  }
6787
6787
  if (entries.length !== descriptors.size) fail("inventory-mismatch");
6788
6788
  const payloads = list(root.files).map((value) => {
@@ -6925,12 +6925,12 @@ async function qualifyModelTextureResources(input, options = {}) {
6925
6925
  ]);
6926
6926
  check();
6927
6927
  const files = new Map(manifest.files.map((file) => [file.path, file]));
6928
- const roles = new Map(inventory.entries.map((entry) => [entry.path, entry.role]));
6929
- for (const entry of inventory.entries) storageRole(entry.role, files.get(entry.path));
6928
+ const roles = new Map(inventory.entries.map((entry2) => [entry2.path, entry2.role]));
6929
+ for (const entry2 of inventory.entries) storageRole(entry2.role, files.get(entry2.path));
6930
6930
  const resources = new Map(graph.nodes.filter((node) => node.kind === "resource").map((node) => [node.id, node.value]));
6931
6931
  if (bindings.length !== resources.size || new Set(bindings.map((b) => b.resourceId)).size !== bindings.length) fail2("resource-mismatch");
6932
6932
  const resourceFiles = /* @__PURE__ */ new Set();
6933
- const qualified = bindings.map((binding) => {
6933
+ const qualified2 = bindings.map((binding) => {
6934
6934
  const value = resources.get(binding.resourceId);
6935
6935
  const file = files.get(binding.filePath);
6936
6936
  if (!value || !file) fail2("resource-mismatch");
@@ -6963,7 +6963,7 @@ async function qualifyModelTextureResources(input, options = {}) {
6963
6963
  contractVersion: 1,
6964
6964
  manifest,
6965
6965
  source: source.value,
6966
- resources: Object.freeze(qualified.sort((a, b) => compare(a.resourceId, b.resourceId))),
6966
+ resources: Object.freeze(qualified2.sort((a, b) => compare(a.resourceId, b.resourceId))),
6967
6967
  materials: Object.freeze(materials),
6968
6968
  textures: Object.freeze(textures),
6969
6969
  derived: Object.freeze(derived.sort((a, b) => compare(a.filePath, b.filePath)))
@@ -6982,6 +6982,9 @@ function tokenPath(value) {
6982
6982
  return value;
6983
6983
  }
6984
6984
 
6985
+ // src/model-resource-promotion.ts
6986
+ import { canonicalizeGpuContract as canonicalizeGpuContract3, computeSha256 as computeSha2562 } from "@plasius/gpu-shader";
6987
+
6985
6988
  // src/model-conversion-diagnostics.ts
6986
6989
  var MODEL_CONVERSION_DIAGNOSTIC_LIMITS = Object.freeze({ issues: 100, resources: 100, values: 16384, depth: 12, string: 2048, characters: 262144, timeoutMs: 6e4 });
6987
6990
  var ModelConversionDiagnosticsError = class extends TypeError {
@@ -7074,9 +7077,9 @@ async function qualifyModelConversionDiagnostics(input, options = {}) {
7074
7077
  only(binding, ["path", "resource"]);
7075
7078
  if (typeof binding.path !== "string" || !binding.path.startsWith("/") || binding.path === "/" || resources.has(binding.path)) fail3();
7076
7079
  const resource = createModelResourceRef(binding.resource);
7077
- const identity = JSON.stringify(resource);
7078
- if (identities.has(resource.uri) && identities.get(resource.uri) !== identity) fail3();
7079
- identities.set(resource.uri, identity);
7080
+ const identity2 = JSON.stringify(resource);
7081
+ if (identities.has(resource.uri) && identities.get(resource.uri) !== identity2) fail3();
7082
+ identities.set(resource.uri, identity2);
7080
7083
  resources.set(binding.path, resource);
7081
7084
  }
7082
7085
  check();
@@ -7129,6 +7132,193 @@ async function qualifyModelConversionDiagnostics(input, options = {}) {
7129
7132
  }
7130
7133
  }
7131
7134
 
7135
+ // src/model-resource-promotion.ts
7136
+ var MODEL_RESOURCE_PROMOTION_LIMITS = Object.freeze({ bindings: 1024, values: 262144, characters: 2097152, depth: 24, timeoutMs: 6e4 });
7137
+ var ModelResourcePromotionError = class extends TypeError {
7138
+ constructor(code) {
7139
+ super(`Invalid model resource promotion: ${code}`);
7140
+ this.code = code;
7141
+ this.name = "ModelResourcePromotionError";
7142
+ }
7143
+ code;
7144
+ };
7145
+ var qualified = /* @__PURE__ */ new WeakSet();
7146
+ function fail4(code = "invalid-input") {
7147
+ throw new ModelResourcePromotionError(code);
7148
+ }
7149
+ function fields3(value, allowed) {
7150
+ if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail4();
7151
+ const keys = Reflect.ownKeys(value);
7152
+ if (keys.length > 1024) fail4("limit-exceeded");
7153
+ const result = /* @__PURE__ */ Object.create(null);
7154
+ for (const key of keys) {
7155
+ if (typeof key !== "string" || key.length > 128 || ["__proto__", "constructor", "prototype"].includes(key) || allowed && !allowed.includes(key)) fail4();
7156
+ const property = Object.getOwnPropertyDescriptor(value, key);
7157
+ if (!("value" in property) || !property.enumerable) fail4();
7158
+ result[key] = property.value;
7159
+ }
7160
+ return result;
7161
+ }
7162
+ function array2(value, maximum) {
7163
+ if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) fail4();
7164
+ if (value.length > maximum) fail4("limit-exceeded");
7165
+ if (Reflect.ownKeys(value).length !== value.length + 1) fail4();
7166
+ return Array.from({ length: value.length }, (_, i) => {
7167
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(i));
7168
+ if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) fail4();
7169
+ return descriptor.value;
7170
+ });
7171
+ }
7172
+ function snapshot4(value, budget, depth = 0) {
7173
+ if (--budget.values < 0 || depth > MODEL_RESOURCE_PROMOTION_LIMITS.depth) fail4("limit-exceeded");
7174
+ if (value === null || value === void 0 || typeof value === "boolean") return value;
7175
+ if (typeof value === "number" && Number.isFinite(value)) return value;
7176
+ if (typeof value === "string") {
7177
+ budget.characters -= value.length;
7178
+ if (value.length > 2048 || budget.characters < 0) fail4("limit-exceeded");
7179
+ return value;
7180
+ }
7181
+ if (Array.isArray(value)) return Object.freeze(array2(value, MODEL_RESOURCE_MANIFEST_LIMITS.files).map((v) => snapshot4(v, budget, depth + 1)));
7182
+ const result = fields3(value);
7183
+ for (const key of Object.keys(result)) {
7184
+ budget.characters -= key.length;
7185
+ if (budget.characters < 0) fail4("limit-exceeded");
7186
+ result[key] = snapshot4(result[key], budget, depth + 1);
7187
+ }
7188
+ return Object.freeze(result);
7189
+ }
7190
+ var typedArrayPrototype2 = Object.getPrototypeOf(Uint8Array.prototype);
7191
+ var byteLengthGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "byteLength").get;
7192
+ var bufferGetter2 = Object.getOwnPropertyDescriptor(typedArrayPrototype2, "buffer").get;
7193
+ function copyFiles(value) {
7194
+ let total = 0;
7195
+ const files = array2(value, MODEL_RESOURCE_MANIFEST_LIMITS.files).map((v) => {
7196
+ const file = fields3(v, ["path", "bytes", "contentType"]);
7197
+ const bytes = file.bytes;
7198
+ if (typeof file.path !== "string" || typeof file.contentType !== "string" || !(bytes instanceof Uint8Array) || Object.getPrototypeOf(bytes) !== Uint8Array.prototype || !(bufferGetter2.call(bytes) instanceof ArrayBuffer)) fail4();
7199
+ const length = byteLengthGetter2.call(bytes);
7200
+ total += length;
7201
+ if (length > MODEL_RESOURCE_MANIFEST_LIMITS.fileBytes || total > MODEL_RESOURCE_MANIFEST_LIMITS.totalBytes) fail4("limit-exceeded");
7202
+ return { path: file.path, bytes, contentType: file.contentType };
7203
+ });
7204
+ return files.map((f) => ({ ...f, bytes: new Uint8Array(f.bytes) }));
7205
+ }
7206
+ var same = (a, b) => canonicalizeGpuContract3(a) === canonicalizeGpuContract3(b);
7207
+ var entry = (m) => m.files.find((f) => f.path === m.entrypoint);
7208
+ var identity = (m) => `${m.assetId}/${m.version}`;
7209
+ async function createModelResourcePromotionRecord(input, options = {}) {
7210
+ let timer;
7211
+ let signal;
7212
+ let onAbort;
7213
+ try {
7214
+ const started = performance.now();
7215
+ const controls = fields3(options, ["signal", "timeoutMs"]);
7216
+ const timeoutMs = controls.timeoutMs === void 0 ? 1e4 : controls.timeoutMs;
7217
+ if (typeof timeoutMs !== "number" || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > MODEL_RESOURCE_PROMOTION_LIMITS.timeoutMs) fail4();
7218
+ signal = controls.signal;
7219
+ const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, "aborted").get;
7220
+ const check = () => {
7221
+ if (signal !== void 0 && aborted.call(signal)) fail4("aborted");
7222
+ if (performance.now() - started >= timeoutMs) fail4("deadline-exceeded");
7223
+ };
7224
+ check();
7225
+ const root = fields3(input, ["promotion", "source", "output", "diagnostics", "resourceBindings", "candidate", "confirmation", "rollback"]);
7226
+ const budget = { values: MODEL_RESOURCE_PROMOTION_LIMITS.values, characters: MODEL_RESOURCE_PROMOTION_LIMITS.characters };
7227
+ const snap = (v) => snapshot4(v, budget);
7228
+ const promotionInput = snap(root.promotion);
7229
+ const sourceInput = fields3(root.source, ["manifest", "packageManifest", "files"]);
7230
+ const outputInput = fields3(root.output, ["manifest", "packageManifest", "files", "graph", "resources", "derived"]);
7231
+ const sourceMetadata = { manifest: snap(sourceInput.manifest), packageManifest: snap(sourceInput.packageManifest) };
7232
+ const outputMetadata = {
7233
+ manifest: snap(outputInput.manifest),
7234
+ packageManifest: snap(outputInput.packageManifest),
7235
+ graph: outputInput.graph,
7236
+ resources: snap(outputInput.resources),
7237
+ derived: snap(outputInput.derived)
7238
+ };
7239
+ const rawDiagnostics = snap(root.diagnostics);
7240
+ const candidate = createModelCandidate(snap(root.candidate));
7241
+ const confirmation = createModelCandidateConfirmation(snap(root.confirmation), candidate, candidate.resolutionId);
7242
+ const bindings = array2(snap(root.resourceBindings), MODEL_RESOURCE_PROMOTION_LIMITS.bindings).map((v) => {
7243
+ const b = fields3(v, ["resource", "package", "filePath"]);
7244
+ if (b.package !== "source" && b.package !== "output" || typeof b.filePath !== "string") fail4();
7245
+ return Object.freeze({ resource: createModelResourceRef(b.resource), package: b.package, filePath: b.filePath });
7246
+ }).sort((a, b) => a.resource.uri < b.resource.uri ? -1 : a.resource.uri > b.resource.uri ? 1 : 0);
7247
+ const history = root.rollback === void 0 ? void 0 : fields3(root.rollback, ["prior", "current"]);
7248
+ if (history && (!qualified.has(history.prior) || !qualified.has(history.current))) fail4("rollback-mismatch");
7249
+ const prior = history?.prior;
7250
+ const current = history?.current;
7251
+ const sourceFiles = copyFiles(sourceInput.files);
7252
+ const outputFiles = copyFiles(outputInput.files);
7253
+ check();
7254
+ const interrupted = new Promise((_resolve, reject) => {
7255
+ timer = setTimeout(() => reject(new ModelResourcePromotionError("deadline-exceeded")), Math.max(1, timeoutMs - (performance.now() - started)));
7256
+ onAbort = () => reject(new ModelResourcePromotionError("aborted"));
7257
+ if (signal) AbortSignal.prototype.addEventListener.call(signal, "abort", onAbort, { once: true });
7258
+ });
7259
+ const work = async () => {
7260
+ const source = await qualifyModelResourceManifest({ ...sourceMetadata, files: sourceFiles, signal, timeoutMs });
7261
+ check();
7262
+ const output = await qualifyModelTextureResources({ ...outputMetadata, files: outputFiles }, { signal, timeoutMs });
7263
+ check();
7264
+ const diagnostics = await qualifyModelConversionDiagnostics(rawDiagnostics, { signal, timeoutMs });
7265
+ check();
7266
+ assertImmutableAssetVersion(source.version);
7267
+ assertImmutableAssetVersion(output.manifest.version);
7268
+ if (identity(source) === identity(output.manifest) || !same(output.manifest, createModelAssetManifest({ ...promotionInput.manifest, files: [...promotionInput.manifest.files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0) })) || output.manifest.assetKind !== "model") fail4("package-mismatch");
7269
+ const converter = candidate.processingManifest.converter;
7270
+ if (!diagnostics.technicalAccepted || !same(diagnostics.source, candidate.provenance) || diagnostics.source.contentHash !== entry(source).sha256 || output.source.sourceContentHash !== entry(source).sha256 || converter.sourceContentHash !== entry(source).sha256 || converter.outputContentHash !== entry(output.manifest).sha256 || converter.id !== output.source.converterId || converter.version !== output.source.converterVersion || converter.sourceFormat !== output.source.sourceFormat || !same(diagnostics.converter.diagnostics, converter.diagnostics) || !same(diagnostics.converter.losses, converter.losses)) fail4("evidence-mismatch");
7271
+ const byUri = /* @__PURE__ */ new Map();
7272
+ for (const binding of bindings) {
7273
+ const file = (binding.package === "source" ? source : output.manifest).files.find((f) => f.path === binding.filePath);
7274
+ if (!file || byUri.has(binding.resource.uri) || file.sha256 !== binding.resource.sha256 || file.byteLength !== binding.resource.byteLength || file.contentType !== binding.resource.contentType) fail4("evidence-mismatch");
7275
+ byUri.set(binding.resource.uri, binding);
7276
+ }
7277
+ const requireResource = (resource, outputOnly = false) => {
7278
+ const binding = byUri.get(resource.uri);
7279
+ if (!binding || !same(binding.resource, resource) || outputOnly && binding.package !== "output") fail4("evidence-mismatch");
7280
+ return binding;
7281
+ };
7282
+ for (const d of diagnostics.diagnostics) if (d.resource) requireResource(d.resource);
7283
+ for (const lod of candidate.processingManifest.lods) requireResource(lod.resource, true);
7284
+ if (candidate.processingManifest.collision.resource) requireResource(candidate.processingManifest.collision.resource, true);
7285
+ for (const f of candidate.processingManifest.fidelityEvidence) if (f.evidenceResource) requireResource(f.evidenceResource, true);
7286
+ if (requireResource(candidate.processingManifest.lods[0].resource, true).filePath !== output.manifest.entrypoint) fail4("evidence-mismatch");
7287
+ if (candidate.assetRef.disposition === "existing" && (candidate.assetRef.asset.assetId !== output.manifest.assetId || candidate.assetRef.asset.version !== output.manifest.version)) fail4("evidence-mismatch");
7288
+ if (promotionInput.sourceAdapter !== output.manifest.sourceAdapter || promotionInput.reviewReport.passed !== true || promotionInput.reviewReport.findings.some((f) => f.severity === "blocking")) fail4("gate-blocked");
7289
+ const expectedSuffix = `/${output.manifest.assetId}/${output.manifest.version}/${output.manifest.entrypoint}`;
7290
+ const runtimeUri = new URL(promotionInput.runtimeManifestUri);
7291
+ if (!runtimeUri.pathname.endsWith(expectedSuffix)) fail4("evidence-mismatch");
7292
+ const promotion = await createGpuAssetPromotionRecord(promotionInput, new Map(outputFiles.map((f) => [f.path, f.bytes])));
7293
+ check();
7294
+ const closure = { contractVersion: 1, source, output, diagnostics, resourceBindings: Object.freeze(bindings), candidate, confirmation };
7295
+ const closureHash = await computeSha2562(new TextEncoder().encode(canonicalizeGpuContract3({ contractVersion: 1, source, output, diagnostics, resourceBindings: bindings })));
7296
+ check();
7297
+ let rollback;
7298
+ if (promotion.outcome === "rolled-back") {
7299
+ if (!prior || !current || prior.promotion.assetId !== promotion.assetId || current.promotion.assetId !== promotion.assetId || prior.promotion.runtimeChannel !== promotion.runtimeChannel || current.promotion.runtimeChannel !== promotion.runtimeChannel || promotion.version !== prior.promotion.version || promotion.version === current.promotion.version || promotion.rollbackOfVersion !== current.promotion.version || closureHash !== prior.closureHash || !same(promotion.manifest, prior.promotion.manifest) || promotion.runtimeManifestUri !== prior.promotion.runtimeManifestUri) fail4("rollback-mismatch");
7300
+ rollback = Object.freeze({ fromVersion: current.promotion.version, fromClosureHash: current.closureHash, toVersion: prior.promotion.version, toClosureHash: prior.closureHash });
7301
+ } else if (history || promotion.rollbackOfVersion !== void 0) fail4("rollback-mismatch");
7302
+ const result = Object.freeze({ ...closure, promotion, closureHash, ...rollback ? { rollback } : {} });
7303
+ qualified.add(result);
7304
+ return result;
7305
+ };
7306
+ return await Promise.race([work(), interrupted]);
7307
+ } catch (error) {
7308
+ let code;
7309
+ try {
7310
+ code = Object.getOwnPropertyDescriptor(error, "code")?.value;
7311
+ } catch {
7312
+ return fail4();
7313
+ }
7314
+ if (["invalid-input", "limit-exceeded", "package-mismatch", "evidence-mismatch", "gate-blocked", "rollback-mismatch", "aborted", "deadline-exceeded"].includes(code)) return fail4(code);
7315
+ return fail4();
7316
+ } finally {
7317
+ if (timer !== void 0) clearTimeout(timer);
7318
+ if (signal && onAbort) AbortSignal.prototype.removeEventListener.call(signal, "abort", onAbort);
7319
+ }
7320
+ }
7321
+
7132
7322
  // src/index.ts
7133
7323
  var ASSET_CONTRACTS_PACKAGE = "@plasius/asset-contracts";
7134
7324
  var UNIFIED_ASSET_PIPELINE_FEATURE_FLAG_ID = "asset.pipeline.unified-ai-assets.enabled";
@@ -7530,7 +7720,7 @@ async function validateGpuAssetFiles(input) {
7530
7720
  if (bytes.byteLength !== file.byteLength) {
7531
7721
  throw new Error(`GPU asset file ${file.path} byte length differs from its descriptor.`);
7532
7722
  }
7533
- if (await computeSha2562(bytes) !== file.sha256) {
7723
+ if (await computeSha2563(bytes) !== file.sha256) {
7534
7724
  throw new Error(`GPU asset file ${file.path} digest differs from its descriptor.`);
7535
7725
  }
7536
7726
  if (file.contentType === ASSET_JSON_CONTENT_TYPE) {
@@ -7550,7 +7740,7 @@ async function validateGpuAssetFiles(input) {
7550
7740
  const expectedDomainManifest = domainManifestForAsset(manifest);
7551
7741
  if (expectedDomainManifest !== null) {
7552
7742
  const parsedEntrypoint = parseJsonBytes(entrypointBytes, "GPU asset manifest entrypoint");
7553
- if (canonicalizeGpuContract3(parsedEntrypoint) !== canonicalizeGpuContract3(expectedDomainManifest)) {
7743
+ if (canonicalizeGpuContract4(parsedEntrypoint) !== canonicalizeGpuContract4(expectedDomainManifest)) {
7554
7744
  throw new Error("GPU asset entrypoint bytes differ from the validated domain manifest.");
7555
7745
  }
7556
7746
  } else if (manifest.assetKind === "shader-validation-evidence") {
@@ -7797,7 +7987,7 @@ function assertEvidenceEntrypointIdentity(value, ref2) {
7797
7987
  function assertCanonicalJsonBytes(bytes, fieldName) {
7798
7988
  const value = parseJsonBytes(bytes, fieldName);
7799
7989
  const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
7800
- if (canonicalizeGpuContract3(value) !== text) {
7990
+ if (canonicalizeGpuContract4(value) !== text) {
7801
7991
  throw new Error(`${fieldName} must use canonical JSON serialization.`);
7802
7992
  }
7803
7993
  }
@@ -7807,10 +7997,10 @@ async function bindDomainManifestBytes(bytes, manifest, fieldName) {
7807
7997
  }
7808
7998
  assertCanonicalJsonBytes(bytes, `${fieldName} manifest`);
7809
7999
  const parsed = parseJsonBytes(bytes, `${fieldName} manifest`);
7810
- if (canonicalizeGpuContract3(parsed) !== canonicalizeGpuContract3(manifest)) {
8000
+ if (canonicalizeGpuContract4(parsed) !== canonicalizeGpuContract4(manifest)) {
7811
8001
  throw new Error(`${fieldName} manifest bytes differ from the supplied manifest.`);
7812
8002
  }
7813
- return computeSha2562(bytes);
8003
+ return computeSha2563(bytes);
7814
8004
  }
7815
8005
  function assertRoleCount(manifest, role, expectedCount) {
7816
8006
  if (manifest.files.filter((file) => file.role === role).length !== expectedCount) {
@@ -7931,11 +8121,13 @@ export {
7931
8121
  MODEL_RESOLUTION_V2_JSON_SCHEMAS,
7932
8122
  MODEL_RESOLUTION_V2_STATES,
7933
8123
  MODEL_RESOURCE_MANIFEST_LIMITS,
8124
+ MODEL_RESOURCE_PROMOTION_LIMITS,
7934
8125
  MODEL_RIGHTS_STATUSES,
7935
8126
  MODEL_TEXTURE_RESOURCE_LIMITS,
7936
8127
  MODEL_TEXT_ONLY_ASSURANCE_CEILING_REASON_CODE,
7937
8128
  ModelConversionDiagnosticsError,
7938
8129
  ModelResourceManifestError,
8130
+ ModelResourcePromotionError,
7939
8131
  ModelTextureResourceError,
7940
8132
  PVOX_ASSEMBLY_CLOSURE_HASH_DOMAIN,
7941
8133
  PVOX_ASSET_MANIFEST_VERSION,
@@ -8071,6 +8263,7 @@ export {
8071
8263
  createModelRequestSpecV2,
8072
8264
  createModelResolution,
8073
8265
  createModelResolutionV2,
8266
+ createModelResourcePromotionRecord,
8074
8267
  createModelResourceRef,
8075
8268
  createModelRightsAssessment,
8076
8269
  createModelTechnicalProfile,