@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.
@@ -1,2 +1,2 @@
1
- export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, type MaterialCookArtifact, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, type MaterialCookVariant, type MaterialCookVariantContext, type MaterialCookWasmProvenance, materialLayerPlanIdentity, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, } from './evidence/material-cook.js';
1
+ export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, createMaterialProgramSetDigest, type MaterialCookArtifact, type MaterialCookProgram, type MaterialCookProgramContext, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, type MaterialCookWasmProvenance, materialLayerPlanIdentity, materialProgramContextKey, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, validateMaterialCookProgramContext, } from './evidence/material-cook.js';
2
2
  //# sourceMappingURL=material-cook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"material-cook.d.ts","sourceRoot":"","sources":["../src/material-cook.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"material-cook.d.ts","sourceRoot":"","sources":["../src/material-cook.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,8BAA8B,EAC9B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,EAC5B,kCAAkC,GACnC,MAAM,6BAA6B,CAAC"}
@@ -7,8 +7,7 @@ var STANDARD_ROOT_MODULES = /* @__PURE__ */ new Set([
7
7
  "forgeax::default-standard-pbr",
8
8
  "forgeax::pbr-skin",
9
9
  "forgeax_material::standard",
10
- "forgeax_material::pbr-skin",
11
- "forgeax::default-shadow-caster"
10
+ "forgeax_material::pbr-skin"
12
11
  ]);
13
12
  function isStandardRootModule(module) {
14
13
  return STANDARD_ROOT_MODULES.has(module);
@@ -107,7 +106,7 @@ function serializeMaterialCookReceipt(receipt) {
107
106
  function invalid(field, actual) {
108
107
  return err({
109
108
  code: "material-cook-record-invalid",
110
- expected: "a complete material-cook/3 record with layered identity and provenance",
109
+ expected: "a complete material-cook/4 record with layered identity and provenance",
111
110
  hint: "re-cook the material and publish its record, artifact, references, and receipt together",
112
111
  detail: {
113
112
  field,
@@ -168,7 +167,7 @@ function validateIdentity(value) {
168
167
  function validateMaterialCookReceipt(value, expected = {}) {
169
168
  if (value === null || typeof value !== "object") return invalid("receipt");
170
169
  const candidate = value;
171
- if (candidate.schemaVersion !== "material-cook/3")
170
+ if (candidate.schemaVersion !== "material-cook/4")
172
171
  return invalid("receipt.schemaVersion", candidate.schemaVersion);
173
172
  const identityResult = validateIdentity(candidate.identity);
174
173
  if (!identityResult.ok) return identityResult;
@@ -206,7 +205,7 @@ function validateMaterialCookReceipt(value, expected = {}) {
206
205
  return invalid("receipt.identity.cookIdentity", identity.cookIdentity);
207
206
  }
208
207
  return ok({
209
- schemaVersion: "material-cook/3",
208
+ schemaVersion: "material-cook/4",
210
209
  sourceClosure: candidate.sourceClosure,
211
210
  profile: candidate.profile,
212
211
  compilerVersion: candidate.compilerVersion,
@@ -220,7 +219,7 @@ function validateMaterialCookReceipt(value, expected = {}) {
220
219
  function validateCookedMaterialRecord(value) {
221
220
  if (value === null || typeof value !== "object") return invalid("record");
222
221
  const candidate = value;
223
- if (candidate.schemaVersion !== "material-cook/3")
222
+ if (candidate.schemaVersion !== "material-cook/4")
224
223
  return invalid("schemaVersion", candidate.schemaVersion);
225
224
  if (typeof candidate.guid !== "string" || !candidate.guid) return invalid("guid");
226
225
  if (candidate.materialGuid !== void 0 && typeof candidate.materialGuid !== "string")
@@ -229,33 +228,8 @@ function validateCookedMaterialRecord(value) {
229
228
  return invalid("publicationGeneration", candidate.publicationGeneration);
230
229
  if (candidate.specializationKey !== void 0 && typeof candidate.specializationKey !== "string")
231
230
  return invalid("specializationKey");
232
- if (candidate.variantContext !== void 0) {
233
- if (candidate.variantContext === null || typeof candidate.variantContext !== "object")
234
- return invalid("variantContext");
235
- const context = candidate.variantContext;
236
- if (context.backend !== "webgpu" && context.backend !== "webgl2" && context.backend !== "wgpu-native" || context.capability !== "storage-buffer" && context.capability !== "uniform-fallback")
237
- return invalid("variantContext", candidate.variantContext);
238
- }
239
- if (candidate.variants !== void 0) {
240
- if (!Array.isArray(candidate.variants)) return invalid("variants");
241
- for (const [index, value2] of candidate.variants.entries()) {
242
- if (value2 === null || typeof value2 !== "object") return invalid(`variants[${index}]`);
243
- const variant = value2;
244
- const context = variant.context;
245
- if (context === null || typeof context !== "object")
246
- return invalid(`variants[${index}].context`);
247
- const contextRecord = context;
248
- if (contextRecord.backend !== "webgpu" && contextRecord.backend !== "webgl2" && contextRecord.backend !== "wgpu-native" || contextRecord.capability !== "storage-buffer" && contextRecord.capability !== "uniform-fallback")
249
- return invalid(`variants[${index}].context`, context);
250
- if (typeof variant.specializationKey !== "string" || variant.specializationKey.length === 0)
251
- return invalid(`variants[${index}].specializationKey`);
252
- if (variant.artifact === null || typeof variant.artifact !== "object")
253
- return invalid(`variants[${index}].artifact`);
254
- const variantArtifact = variant.artifact;
255
- if (typeof variantArtifact.mediaType !== "string" || typeof variantArtifact.path !== "string" || typeof variantArtifact.digest !== "string" || normalizeArtifactBytes(variantArtifact.bytes) === void 0)
256
- return invalid(`variants[${index}].artifact`);
257
- }
258
- }
231
+ if ("artifact" in candidate || "variants" in candidate || "variantContext" in candidate)
232
+ return invalid("programs", "legacy single-artifact publication");
259
233
  if (candidate.artifactDigest !== void 0 && typeof candidate.artifactDigest !== "string")
260
234
  return invalid("artifactDigest");
261
235
  if (candidate.sourceClosure !== void 0 && (!Array.isArray(candidate.sourceClosure) || candidate.sourceClosure.some((path) => typeof path !== "string")))
@@ -272,24 +246,72 @@ function validateCookedMaterialRecord(value) {
272
246
  if (candidate.resolved === null || typeof candidate.resolved !== "object")
273
247
  return invalid("resolved");
274
248
  if (candidate.refs === null || typeof candidate.refs !== "object") return invalid("refs");
275
- if (candidate.artifact === null || typeof candidate.artifact !== "object")
276
- return invalid("artifact");
277
249
  if (candidate.receipt === null || typeof candidate.receipt !== "object")
278
250
  return invalid("receipt");
279
- const artifact = candidate.artifact;
280
- if (typeof artifact.digest !== "string" || !Array.isArray(artifact.bytes) && !ArrayBuffer.isView(artifact.bytes)) {
281
- return invalid("artifact");
282
- }
283
- const receiptResult = validateMaterialCookReceipt(candidate.receipt, {
284
- artifactDigest: artifact.digest
285
- });
286
- if (!receiptResult.ok) return receiptResult;
287
251
  const resolved = candidate.resolved;
288
252
  if (!Array.isArray(resolved.passes)) return invalid("resolved.passes", resolved.passes);
289
253
  if (!Array.isArray(resolved.parameters))
290
254
  return invalid("resolved.parameters", resolved.parameters);
291
255
  if (resolved.values === null || typeof resolved.values !== "object" || Array.isArray(resolved.values))
292
256
  return invalid("resolved.values", resolved.values);
257
+ const passes = resolved.passes;
258
+ const passNames = /* @__PURE__ */ new Set();
259
+ for (const [index, pass] of passes.entries()) {
260
+ 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")
261
+ return invalid(`resolved.passes[${index}]`);
262
+ passNames.add(pass.name);
263
+ }
264
+ if (!Array.isArray(candidate.programs) || candidate.programs.length === 0)
265
+ return invalid("programs");
266
+ const programs = [];
267
+ const programKeys = /* @__PURE__ */ new Set();
268
+ const selections = /* @__PURE__ */ new Set();
269
+ const selectedPasses = /* @__PURE__ */ new Set();
270
+ for (const [index, entry] of candidate.programs.entries()) {
271
+ const field = `programs[${index}]`;
272
+ if (entry === null || typeof entry !== "object") return invalid(field);
273
+ const program = entry;
274
+ if (typeof program.specializationKey !== "string" || !program.specializationKey || programKeys.has(program.specializationKey))
275
+ return invalid(`${field}.specializationKey`);
276
+ programKeys.add(program.specializationKey);
277
+ if (program.artifact === null || typeof program.artifact !== "object")
278
+ return invalid(`${field}.artifact`);
279
+ const artifact = program.artifact;
280
+ const bytes = normalizeArtifactBytes(artifact.bytes);
281
+ if (artifact.mediaType !== "text/wgsl" || typeof artifact.path !== "string" || !artifact.path || typeof artifact.digest !== "string" || !artifact.digest || bytes === void 0)
282
+ return invalid(`${field}.artifact`);
283
+ if (!Array.isArray(program.selections) || program.selections.length === 0)
284
+ return invalid(`${field}.selections`);
285
+ const programSelections = [];
286
+ for (const [selectionIndex, selection] of program.selections.entries()) {
287
+ const selectionField = `${field}.selections[${selectionIndex}]`;
288
+ if (selection === null || typeof selection !== "object" || !passNames.has(selection.pass))
289
+ return invalid(selectionField);
290
+ const context = validateMaterialCookProgramContext(selection.context);
291
+ if (!context.ok)
292
+ return invalid(
293
+ `${selectionField}.${context.error.detail.field}`,
294
+ context.error.detail.actual
295
+ );
296
+ const key = JSON.stringify([selection.pass, materialProgramContextKey(context.value)]);
297
+ if (selections.has(key)) return invalid(selectionField, "ambiguous Pass/context selection");
298
+ selections.add(key);
299
+ selectedPasses.add(selection.pass);
300
+ programSelections.push({ pass: selection.pass, context: context.value });
301
+ }
302
+ programs.push({
303
+ specializationKey: program.specializationKey,
304
+ artifact: { mediaType: "text/wgsl", path: artifact.path, digest: artifact.digest, bytes },
305
+ selections: programSelections
306
+ });
307
+ }
308
+ if ([...passNames].some((pass) => !selectedPasses.has(pass)))
309
+ return invalid("programs.selections", "unpublished Pass");
310
+ const manifestDigest = createMaterialProgramSetDigest(programs, passes);
311
+ const receiptResult = validateMaterialCookReceipt(candidate.receipt, {
312
+ artifactDigest: manifestDigest
313
+ });
314
+ if (!receiptResult.ok) return receiptResult;
293
315
  let expectedLayerPlanIdentity;
294
316
  try {
295
317
  expectedLayerPlanIdentity = materialLayerPlanIdentity({
@@ -304,45 +326,71 @@ function validateCookedMaterialRecord(value) {
304
326
  receiptResult.value.derivedInterface.layerPlanIdentity
305
327
  );
306
328
  }
307
- if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !== artifact.digest)
329
+ if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !== manifestDigest)
308
330
  return invalid("artifactDigest", candidate.artifactDigest);
309
331
  if (candidate.publicationGeneration !== void 0 && receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration)
310
332
  return invalid("receipt.identity.cookGeneration", receiptResult.value.identity.cookGeneration);
311
- const normalized = {
333
+ return ok({
312
334
  ...candidate,
313
- artifact: {
314
- ...artifact,
315
- bytes: normalizeArtifactBytes(artifact.bytes)
316
- },
317
- ...Array.isArray(candidate.variants) ? {
318
- variants: candidate.variants.map((value2) => {
319
- const variant = value2;
320
- const variantArtifact = variant.artifact;
321
- return {
322
- ...variant,
323
- artifact: {
324
- ...variantArtifact,
325
- bytes: normalizeArtifactBytes(variantArtifact.bytes)
326
- }
327
- };
328
- })
329
- } : {},
335
+ programs,
330
336
  receipt: receiptResult.value
331
- };
332
- return ok(normalized);
337
+ });
333
338
  }
334
339
  function projectCookedMaterialRecord(record) {
335
340
  return {
336
341
  resolved: record.resolved,
337
342
  refs: record.refs,
338
- artifact: record.artifact,
339
- ...record.variantContext === void 0 ? {} : { variantContext: record.variantContext },
340
- ...record.variants === void 0 ? {} : { variants: record.variants },
343
+ programs: record.programs,
341
344
  receipt: record.receipt,
342
345
  schemaVersion: record.schemaVersion
343
346
  };
344
347
  }
348
+ function materialProgramContextKey(context) {
349
+ return JSON.stringify(jsonValue(context));
350
+ }
351
+ function validateMaterialCookProgramContext(value) {
352
+ if (value === null || typeof value !== "object" || Array.isArray(value))
353
+ return invalid("context", value);
354
+ const context = value;
355
+ const fields = {
356
+ backend: ["webgpu", "webgl2", "wgpu-native"],
357
+ capability: ["storage-buffer", "uniform-fallback"],
358
+ pipeline: ["forward", "deferred"],
359
+ geometry: ["mesh", "skinned", "sprite"],
360
+ pass: ["forward", "shadow", "depth"],
361
+ profile: ["forgeax-material-wgsl-v1"],
362
+ toolchain: ["naga-oil"],
363
+ instrumentation: ["none", "validation"]
364
+ };
365
+ for (const field of Object.keys(context)) {
366
+ if (!(field in fields)) return invalid(`context.${field}`, context[field]);
367
+ }
368
+ for (const [field, allowed] of Object.entries(fields)) {
369
+ if (!allowed.includes(context[field]))
370
+ return invalid(`context.${field}`, context[field]);
371
+ }
372
+ return ok({ ...context });
373
+ }
374
+ function createMaterialProgramSetDigest(programs, passes) {
375
+ const manifest = {
376
+ passes,
377
+ programs: programs.map((program) => ({
378
+ specializationKey: program.specializationKey,
379
+ artifact: {
380
+ path: program.artifact.path,
381
+ mediaType: program.artifact.mediaType,
382
+ digest: program.artifact.digest
383
+ },
384
+ selections: [...program.selections].sort(
385
+ (a, b) => JSON.stringify(jsonValue(a)).localeCompare(JSON.stringify(jsonValue(b)))
386
+ )
387
+ })).sort((a, b) => a.specializationKey.localeCompare(b.specializationKey))
388
+ };
389
+ return createMaterialArtifactDigest(
390
+ new TextEncoder().encode(JSON.stringify(jsonValue(manifest)))
391
+ );
392
+ }
345
393
 
346
- export { collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, materialLayerPlanIdentity, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord };
394
+ export { collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, createMaterialProgramSetDigest, materialLayerPlanIdentity, materialProgramContextKey, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, validateMaterialCookProgramContext };
347
395
  //# sourceMappingURL=material-cook.mjs.map
348
396
  //# sourceMappingURL=material-cook.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/evidence/material-cook.ts"],"names":["value"],"mappings":"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","file":"material-cook.mjs","sourcesContent":["import type {\n MaterialAsset,\n MaterialParameter,\n MaterialPass,\n MaterialTextureReference,\n MaterialTextureValue,\n MaterialValue,\n Result,\n} from '@forgeax/engine-types';\nimport { deriveStandardLayerPlan, err, MATERIAL_TEXTURE_SLOTS, ok } from '@forgeax/engine-types';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { bytesToHex } from '@noble/hashes/utils.js';\n\nexport interface MaterialCookRefs {\n readonly parent: readonly string[];\n readonly textures: readonly string[];\n readonly samplers: readonly string[];\n readonly modules: readonly string[];\n}\n\nexport interface MaterialCookArtifact {\n readonly mediaType: string;\n readonly path: string;\n readonly digest: string;\n readonly bytes: Uint8Array;\n}\n\n/** Backend capability projection for one immutable cooked material artifact. */\nexport interface MaterialCookVariantContext {\n readonly backend: 'webgpu' | 'webgl2' | 'wgpu-native';\n readonly capability: 'storage-buffer' | 'uniform-fallback';\n}\n\n/** Additional backend artifact published with one material generation. */\nexport interface MaterialCookVariant {\n readonly context: MaterialCookVariantContext;\n readonly specializationKey: string;\n readonly artifact: MaterialCookArtifact;\n}\n\nexport interface MaterialCookWasmProvenance {\n readonly sourceContentKey: string;\n readonly artifactSha256: string;\n readonly glueSha256: string;\n}\n\nexport interface MaterialCookIdentity {\n readonly materialContractDigest: string;\n readonly sourceRevision: string;\n readonly sourceClosureDigest: string;\n readonly layoutIdentity: string;\n readonly programIdentity: string;\n readonly pipelineIdentity: string;\n readonly materialPublicationIdentity: string;\n readonly cookIdentity: string;\n readonly compilerFingerprint: string;\n readonly wasm: MaterialCookWasmProvenance;\n readonly artifactDigest: string;\n readonly valueGeneration: number;\n readonly dependencyGeneration: number;\n readonly cookGeneration: number;\n}\n\nexport type MaterialCookIdentityInput = Omit<MaterialCookIdentity, 'cookIdentity'>;\n\nexport interface MaterialCookReceipt {\n readonly schemaVersion: 'material-cook/3';\n readonly sourceClosure: readonly string[];\n readonly profile: string;\n readonly compilerVersion: string;\n readonly identity: MaterialCookIdentity;\n readonly derivedInterface: {\n readonly layoutIdentity: string;\n /** Build-time Standard physical lowering identity, when the root is Standard. */\n readonly layerPlanIdentity?: string;\n };\n}\n\nexport interface MaterialParameterContract {\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n}\n\nexport interface CookedMaterialRecord {\n readonly schemaVersion: 'material-cook/3';\n readonly guid: string;\n readonly authored?: MaterialAsset;\n readonly materialGuid?: string;\n readonly publicationGeneration?: number;\n readonly specializationKey?: string;\n /** Compiler context used by the primary `artifact` entry. */\n readonly variantContext?: MaterialCookVariantContext;\n /** Additional immutable artifacts for other backend capability lanes. */\n readonly variants?: readonly MaterialCookVariant[];\n readonly artifactDigest?: string;\n readonly sourceClosure?: readonly string[];\n readonly parameterContract?: MaterialParameterContract;\n readonly resolved: {\n readonly passes: readonly MaterialPass[];\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n };\n readonly refs: MaterialCookRefs;\n readonly artifact: MaterialCookArtifact;\n readonly receipt: MaterialCookReceipt;\n}\n\nexport interface MaterialCookRecordError {\n readonly code: 'material-cook-record-invalid';\n readonly expected: string;\n readonly hint: string;\n readonly detail: {\n readonly field: string;\n readonly actual?: unknown;\n readonly action: string;\n };\n}\n\nexport interface MaterialCookIdentityExpectation {\n readonly layoutIdentity?: string;\n readonly artifactDigest?: string;\n readonly inputDigest?: string;\n}\n\nconst STANDARD_ROOT_MODULES = new Set([\n 'forgeax::default-standard-pbr',\n 'forgeax::pbr-skin',\n 'forgeax_material::standard',\n 'forgeax_material::pbr-skin',\n 'forgeax::default-shadow-caster',\n]);\n\n/** Shared ownership predicate for the built-in Standard material root. */\nexport function isStandardRootModule(module: string): boolean {\n return STANDARD_ROOT_MODULES.has(module);\n}\n\nexport function isStandardMaterialRecord(record: Pick<CookedMaterialRecord, 'resolved'>): boolean {\n return record.resolved.passes.some((pass) => isStandardRootModule(pass.program.module));\n}\n\n/**\n * Recompute the Standard layer identity from the admitted resolved root.\n * Material admission and runtime loading share this owner so a stale receipt\n * cannot select a different physical layer plan after cooking.\n */\nexport function materialLayerPlanIdentity(\n record: Pick<CookedMaterialRecord, 'resolved'>,\n): string | undefined {\n if (!isStandardMaterialRecord(record)) {\n return undefined;\n }\n return deriveStandardLayerPlan(record.resolved.parameters, record.resolved.passes).identity;\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n return [...new Set(values)].sort();\n}\n\nfunction guidText(value: string | Uint8Array): string {\n return typeof value === 'string'\n ? value\n : Array.from(value, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nfunction cookGuidText(value: MaterialTextureReference): string | undefined {\n return typeof value === 'number' ? undefined : guidText(value);\n}\n\nfunction textureValues(\n values: Readonly<Record<string, MaterialValue | null>> | undefined,\n textureFields: ReadonlySet<string>,\n): readonly MaterialTextureValue[] {\n return Object.entries(values ?? {}).flatMap(([name, value]) => {\n if (value === null) return [];\n if (typeof value === 'string') {\n return textureFields.has(name) ? [{ texture: value }] : [];\n }\n return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n 'texture' in value\n ? [value as MaterialTextureValue]\n : [];\n });\n}\n\nexport function collectMaterialCookRefs(material: Partial<MaterialAsset>): MaterialCookRefs {\n const textureFields =\n material.parameters === undefined\n ? new Set<string>(MATERIAL_TEXTURE_SLOTS)\n : new Set(\n material.parameters\n .filter(\n (parameter) => parameter.type === 'texture' || parameter.type === 'texture_cube',\n )\n .map((parameter) => parameter.name),\n );\n const textures = textureValues(material.values, textureFields);\n return {\n parent: material.parent ? [guidText(material.parent)] : [],\n textures: unique(\n textures.flatMap((value) => {\n const guid = cookGuidText(value.texture);\n return guid === undefined ? [] : [guid];\n }),\n ),\n samplers: unique(\n textures.flatMap((value) => {\n if (value.sampler === undefined) return [];\n const guid = cookGuidText(value.sampler);\n return guid === undefined ? [] : [guid];\n }),\n ),\n modules: unique((material.passes ?? []).map((pass) => pass.program.module)),\n };\n}\n\nexport function createMaterialArtifactDigest(bytes: Uint8Array): string {\n return `sha256:${bytesToHex(sha256(bytes))}`;\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return [...value];\n if (Array.isArray(value)) return value.map(jsonValue);\n if (value !== null && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, entry]) => entry !== undefined)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, jsonValue(entry)]),\n );\n }\n return value;\n}\n\nexport function createMaterialCookIdentity(input: MaterialCookIdentityInput): MaterialCookIdentity {\n const cookIdentity = createMaterialArtifactDigest(\n new TextEncoder().encode(\n JSON.stringify(\n jsonValue({\n materialContractDigest: input.materialContractDigest,\n sourceRevision: input.sourceRevision,\n sourceClosureDigest: input.sourceClosureDigest,\n layoutIdentity: input.layoutIdentity,\n programIdentity: input.programIdentity,\n pipelineIdentity: input.pipelineIdentity,\n compilerFingerprint: input.compilerFingerprint,\n wasm: input.wasm,\n artifactDigest: input.artifactDigest,\n }),\n ),\n ),\n );\n return { ...input, cookIdentity };\n}\n\nexport function serializeCookedMaterialRecord(record: CookedMaterialRecord): string {\n return JSON.stringify(jsonValue(record));\n}\n\nexport function serializeMaterialCookReceipt(receipt: MaterialCookReceipt): string {\n return JSON.stringify(jsonValue({ ...receipt, sourceClosure: unique(receipt.sourceClosure) }));\n}\n\nfunction invalid(field: string, actual?: unknown): Result<never, MaterialCookRecordError> {\n return err({\n code: 'material-cook-record-invalid',\n expected: 'a complete material-cook/3 record with layered identity and provenance',\n hint: 're-cook the material and publish its record, artifact, references, and receipt together',\n detail: {\n field,\n ...(actual === undefined ? {} : { actual }),\n action: 'inspect the named field and recook the material generation',\n },\n });\n}\n\nfunction normalizeArtifactBytes(value: unknown): Uint8Array | undefined {\n if (Array.isArray(value)) {\n return value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)\n ? Uint8Array.from(value)\n : undefined;\n }\n if (!ArrayBuffer.isView(value)) return undefined;\n const view = value as ArrayBufferView;\n return new Uint8Array(view.buffer, view.byteOffset, view.byteLength).slice();\n}\n\nconst IDENTITY_FIELDS = [\n 'materialContractDigest',\n 'sourceRevision',\n 'sourceClosureDigest',\n 'layoutIdentity',\n 'programIdentity',\n 'pipelineIdentity',\n 'materialPublicationIdentity',\n 'cookIdentity',\n 'compilerFingerprint',\n 'artifactDigest',\n] as const;\n\nfunction isGeneration(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1;\n}\n\nfunction validateIdentity(value: unknown): Result<MaterialCookIdentity, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt.identity', value);\n const candidate = value as Record<string, unknown>;\n for (const field of IDENTITY_FIELDS) {\n if (typeof candidate[field] !== 'string' || candidate[field].length === 0) {\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n }\n if (candidate.wasm === null || typeof candidate.wasm !== 'object') {\n return invalid('receipt.identity.wasm', candidate.wasm);\n }\n const wasm = candidate.wasm as Record<string, unknown>;\n for (const field of ['sourceContentKey', 'artifactSha256', 'glueSha256']) {\n if (typeof wasm[field] !== 'string' || wasm[field].length === 0) {\n return invalid(`receipt.identity.wasm.${field}`, wasm[field]);\n }\n }\n for (const field of ['valueGeneration', 'dependencyGeneration', 'cookGeneration']) {\n if (!isGeneration(candidate[field]))\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n return ok({\n ...candidate,\n wasm: wasm as unknown as MaterialCookWasmProvenance,\n } as MaterialCookIdentity);\n}\n\nexport function validateMaterialCookReceipt(\n value: unknown,\n expected: MaterialCookIdentityExpectation = {},\n): Result<MaterialCookReceipt, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/3')\n return invalid('receipt.schemaVersion', candidate.schemaVersion);\n const identityResult = validateIdentity(candidate.identity);\n if (!identityResult.ok) return identityResult;\n const identity = identityResult.value;\n if (candidate.derivedInterface === null || typeof candidate.derivedInterface !== 'object') {\n return invalid('receipt.derivedInterface', candidate.derivedInterface);\n }\n const derivedInterface = candidate.derivedInterface as Record<string, unknown>;\n if (derivedInterface.layoutIdentity !== identity.layoutIdentity) {\n return invalid('receipt.derivedInterface.layoutIdentity', derivedInterface.layoutIdentity);\n }\n if (\n derivedInterface.layerPlanIdentity !== undefined &&\n (typeof derivedInterface.layerPlanIdentity !== 'string' ||\n derivedInterface.layerPlanIdentity.length === 0)\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n derivedInterface.layerPlanIdentity,\n );\n }\n for (const field of ['sourceClosure', 'profile', 'compilerVersion']) {\n const fieldValue = candidate[field];\n if (\n (field === 'sourceClosure' && !Array.isArray(fieldValue)) ||\n (field !== 'sourceClosure' && typeof fieldValue !== 'string')\n ) {\n return invalid(`receipt.${field}`, fieldValue);\n }\n }\n const sourceClosure = candidate.sourceClosure;\n if (Array.isArray(sourceClosure) && sourceClosure.some((path) => typeof path !== 'string')) {\n return invalid('receipt.sourceClosure', sourceClosure);\n }\n if (\n expected.layoutIdentity !== undefined &&\n identity.layoutIdentity !== expected.layoutIdentity\n ) {\n return invalid('receipt.identity.layoutIdentity', identity.layoutIdentity);\n }\n if (\n expected.artifactDigest !== undefined &&\n identity.artifactDigest !== expected.artifactDigest\n ) {\n return invalid('receipt.identity.artifactDigest', identity.artifactDigest);\n }\n if (expected.inputDigest !== undefined && identity.cookIdentity !== expected.inputDigest) {\n return invalid('receipt.identity.cookIdentity', identity.cookIdentity);\n }\n return ok({\n schemaVersion: 'material-cook/3',\n sourceClosure: candidate.sourceClosure as string[],\n profile: candidate.profile as string,\n compilerVersion: candidate.compilerVersion as string,\n identity,\n derivedInterface: {\n layoutIdentity: derivedInterface.layoutIdentity as string,\n ...(derivedInterface.layerPlanIdentity === undefined\n ? {}\n : { layerPlanIdentity: derivedInterface.layerPlanIdentity as string }),\n },\n });\n}\n\nexport function validateCookedMaterialRecord(\n value: unknown,\n): Result<CookedMaterialRecord, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('record');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/3')\n return invalid('schemaVersion', candidate.schemaVersion);\n if (typeof candidate.guid !== 'string' || !candidate.guid) return invalid('guid');\n if (candidate.materialGuid !== undefined && typeof candidate.materialGuid !== 'string')\n return invalid('materialGuid');\n if (\n candidate.publicationGeneration !== undefined &&\n !isGeneration(candidate.publicationGeneration)\n )\n return invalid('publicationGeneration', candidate.publicationGeneration);\n if (candidate.specializationKey !== undefined && typeof candidate.specializationKey !== 'string')\n return invalid('specializationKey');\n if (candidate.variantContext !== undefined) {\n if (candidate.variantContext === null || typeof candidate.variantContext !== 'object')\n return invalid('variantContext');\n const context = candidate.variantContext as Record<string, unknown>;\n if (\n (context.backend !== 'webgpu' &&\n context.backend !== 'webgl2' &&\n context.backend !== 'wgpu-native') ||\n (context.capability !== 'storage-buffer' && context.capability !== 'uniform-fallback')\n )\n return invalid('variantContext', candidate.variantContext);\n }\n if (candidate.variants !== undefined) {\n if (!Array.isArray(candidate.variants)) return invalid('variants');\n for (const [index, value] of candidate.variants.entries()) {\n if (value === null || typeof value !== 'object') return invalid(`variants[${index}]`);\n const variant = value as Record<string, unknown>;\n const context = variant.context;\n if (context === null || typeof context !== 'object')\n return invalid(`variants[${index}].context`);\n const contextRecord = context as Record<string, unknown>;\n if (\n (contextRecord.backend !== 'webgpu' &&\n contextRecord.backend !== 'webgl2' &&\n contextRecord.backend !== 'wgpu-native') ||\n (contextRecord.capability !== 'storage-buffer' &&\n contextRecord.capability !== 'uniform-fallback')\n )\n return invalid(`variants[${index}].context`, context);\n if (typeof variant.specializationKey !== 'string' || variant.specializationKey.length === 0)\n return invalid(`variants[${index}].specializationKey`);\n if (variant.artifact === null || typeof variant.artifact !== 'object')\n return invalid(`variants[${index}].artifact`);\n const variantArtifact = variant.artifact as Record<string, unknown>;\n if (\n typeof variantArtifact.mediaType !== 'string' ||\n typeof variantArtifact.path !== 'string' ||\n typeof variantArtifact.digest !== 'string' ||\n normalizeArtifactBytes(variantArtifact.bytes) === undefined\n )\n return invalid(`variants[${index}].artifact`);\n }\n }\n if (candidate.artifactDigest !== undefined && typeof candidate.artifactDigest !== 'string')\n return invalid('artifactDigest');\n if (\n candidate.sourceClosure !== undefined &&\n (!Array.isArray(candidate.sourceClosure) ||\n candidate.sourceClosure.some((path) => typeof path !== 'string'))\n )\n return invalid('sourceClosure');\n if (candidate.parameterContract !== undefined) {\n if (candidate.parameterContract === null || typeof candidate.parameterContract !== 'object')\n return invalid('parameterContract');\n const parameterContract = candidate.parameterContract as Record<string, unknown>;\n if (!Array.isArray(parameterContract.parameters))\n return invalid('parameterContract.parameters');\n if (\n parameterContract.values === null ||\n typeof parameterContract.values !== 'object' ||\n Array.isArray(parameterContract.values)\n )\n return invalid('parameterContract.values');\n }\n if (candidate.resolved === null || typeof candidate.resolved !== 'object')\n return invalid('resolved');\n if (candidate.refs === null || typeof candidate.refs !== 'object') return invalid('refs');\n if (candidate.artifact === null || typeof candidate.artifact !== 'object')\n return invalid('artifact');\n if (candidate.receipt === null || typeof candidate.receipt !== 'object')\n return invalid('receipt');\n const artifact = candidate.artifact as Record<string, unknown>;\n if (\n typeof artifact.digest !== 'string' ||\n (!Array.isArray(artifact.bytes) && !ArrayBuffer.isView(artifact.bytes))\n ) {\n return invalid('artifact');\n }\n const receiptResult = validateMaterialCookReceipt(candidate.receipt, {\n artifactDigest: artifact.digest as string,\n });\n if (!receiptResult.ok) return receiptResult;\n const resolved = candidate.resolved as Record<string, unknown>;\n if (!Array.isArray(resolved.passes)) return invalid('resolved.passes', resolved.passes);\n if (!Array.isArray(resolved.parameters))\n return invalid('resolved.parameters', resolved.parameters);\n if (\n resolved.values === null ||\n typeof resolved.values !== 'object' ||\n Array.isArray(resolved.values)\n )\n return invalid('resolved.values', resolved.values);\n let expectedLayerPlanIdentity: string | undefined;\n try {\n expectedLayerPlanIdentity = materialLayerPlanIdentity({\n resolved: resolved as unknown as CookedMaterialRecord['resolved'],\n });\n } catch (error) {\n return invalid('resolved.layerPlanIdentity', error instanceof Error ? error.message : error);\n }\n if (\n expectedLayerPlanIdentity !== undefined &&\n receiptResult.value.derivedInterface.layerPlanIdentity !== expectedLayerPlanIdentity\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n receiptResult.value.derivedInterface.layerPlanIdentity,\n );\n }\n if (candidate.artifactDigest !== undefined && candidate.artifactDigest !== artifact.digest)\n return invalid('artifactDigest', candidate.artifactDigest);\n if (\n candidate.publicationGeneration !== undefined &&\n receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration\n )\n return invalid('receipt.identity.cookGeneration', receiptResult.value.identity.cookGeneration);\n const normalized = {\n ...candidate,\n artifact: {\n ...artifact,\n bytes: normalizeArtifactBytes(artifact.bytes) as Uint8Array,\n },\n ...(Array.isArray(candidate.variants)\n ? {\n variants: candidate.variants.map((value) => {\n const variant = value as Record<string, unknown>;\n const variantArtifact = variant.artifact as Record<string, unknown>;\n return {\n ...variant,\n artifact: {\n ...variantArtifact,\n bytes: normalizeArtifactBytes(variantArtifact.bytes) as Uint8Array,\n },\n };\n }),\n }\n : {}),\n receipt: receiptResult.value,\n } as unknown as CookedMaterialRecord;\n return ok(normalized);\n}\n\nexport function projectCookedMaterialRecord(\n record: CookedMaterialRecord,\n): Omit<CookedMaterialRecord, 'guid' | 'authored'> {\n return {\n resolved: record.resolved,\n refs: record.refs,\n artifact: record.artifact,\n ...(record.variantContext === undefined ? {} : { variantContext: record.variantContext }),\n ...(record.variants === undefined ? {} : { variants: record.variants }),\n receipt: record.receipt,\n schemaVersion: record.schemaVersion,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/evidence/material-cook.ts"],"names":[],"mappings":"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","file":"material-cook.mjs","sourcesContent":["import type {\n MaterialAsset,\n MaterialParameter,\n MaterialPass,\n MaterialTextureReference,\n MaterialTextureValue,\n MaterialValue,\n Result,\n} from '@forgeax/engine-types';\nimport { deriveStandardLayerPlan, err, MATERIAL_TEXTURE_SLOTS, ok } from '@forgeax/engine-types';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { bytesToHex } from '@noble/hashes/utils.js';\n\nexport interface MaterialCookRefs {\n readonly parent: readonly string[];\n readonly textures: readonly string[];\n readonly samplers: readonly string[];\n readonly modules: readonly string[];\n}\n\nexport interface MaterialCookArtifact {\n readonly mediaType: string;\n readonly path: string;\n readonly digest: string;\n readonly bytes: Uint8Array;\n}\n\n/** Domain-owned inputs used to compile and select a material program. */\nexport interface MaterialCookProgramContext {\n readonly backend: 'webgpu' | 'webgl2' | 'wgpu-native';\n readonly capability: 'storage-buffer' | 'uniform-fallback';\n readonly pipeline: 'forward' | 'deferred';\n readonly geometry: 'mesh' | 'skinned' | 'sprite';\n readonly pass: 'forward' | 'shadow' | 'depth';\n readonly profile: 'forgeax-material-wgsl-v1';\n readonly toolchain: 'naga-oil';\n readonly instrumentation: 'none' | 'validation';\n}\n\n/** Programs are derived artifacts, never independently authored assets. */\nexport interface MaterialCookProgram {\n readonly specializationKey: string;\n readonly artifact: MaterialCookArtifact;\n readonly selections: readonly {\n readonly pass: string;\n readonly context: MaterialCookProgramContext;\n }[];\n}\n\nexport interface MaterialCookWasmProvenance {\n readonly sourceContentKey: string;\n readonly artifactSha256: string;\n readonly glueSha256: string;\n}\n\nexport interface MaterialCookIdentity {\n readonly materialContractDigest: string;\n readonly sourceRevision: string;\n readonly sourceClosureDigest: string;\n readonly layoutIdentity: string;\n readonly programIdentity: string;\n readonly pipelineIdentity: string;\n readonly materialPublicationIdentity: string;\n readonly cookIdentity: string;\n readonly compilerFingerprint: string;\n readonly wasm: MaterialCookWasmProvenance;\n readonly artifactDigest: string;\n readonly valueGeneration: number;\n readonly dependencyGeneration: number;\n readonly cookGeneration: number;\n}\n\nexport type MaterialCookIdentityInput = Omit<MaterialCookIdentity, 'cookIdentity'>;\n\nexport interface MaterialCookReceipt {\n readonly schemaVersion: 'material-cook/4';\n readonly sourceClosure: readonly string[];\n readonly profile: string;\n readonly compilerVersion: string;\n readonly identity: MaterialCookIdentity;\n readonly derivedInterface: {\n readonly layoutIdentity: string;\n /** Build-time Standard physical lowering identity, when the root is Standard. */\n readonly layerPlanIdentity?: string;\n };\n}\n\nexport interface MaterialParameterContract {\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n}\n\nexport interface CookedMaterialRecord {\n readonly schemaVersion: 'material-cook/4';\n readonly guid: string;\n readonly authored?: MaterialAsset;\n readonly materialGuid?: string;\n readonly publicationGeneration?: number;\n readonly specializationKey?: string;\n readonly programs: readonly MaterialCookProgram[];\n /** Digest of the complete program/Pass/context manifest. */\n readonly artifactDigest?: string;\n readonly sourceClosure?: readonly string[];\n readonly parameterContract?: MaterialParameterContract;\n readonly resolved: {\n readonly passes: readonly MaterialPass[];\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n };\n readonly refs: MaterialCookRefs;\n readonly receipt: MaterialCookReceipt;\n}\n\nexport interface MaterialCookRecordError {\n readonly code: 'material-cook-record-invalid';\n readonly expected: string;\n readonly hint: string;\n readonly detail: {\n readonly field: string;\n readonly actual?: unknown;\n readonly action: string;\n };\n}\n\nexport interface MaterialCookIdentityExpectation {\n readonly layoutIdentity?: string;\n readonly artifactDigest?: string;\n readonly inputDigest?: string;\n}\n\nconst STANDARD_ROOT_MODULES = new Set([\n 'forgeax::default-standard-pbr',\n 'forgeax::pbr-skin',\n 'forgeax_material::standard',\n 'forgeax_material::pbr-skin',\n]);\n\n/** Shared ownership predicate for the built-in Standard material root. */\nexport function isStandardRootModule(module: string): boolean {\n return STANDARD_ROOT_MODULES.has(module);\n}\n\nexport function isStandardMaterialRecord(record: Pick<CookedMaterialRecord, 'resolved'>): boolean {\n return record.resolved.passes.some((pass) => isStandardRootModule(pass.program.module));\n}\n\n/**\n * Recompute the Standard layer identity from the admitted resolved root.\n * Material admission and runtime loading share this owner so a stale receipt\n * cannot select a different physical layer plan after cooking.\n */\nexport function materialLayerPlanIdentity(\n record: Pick<CookedMaterialRecord, 'resolved'>,\n): string | undefined {\n if (!isStandardMaterialRecord(record)) {\n return undefined;\n }\n return deriveStandardLayerPlan(record.resolved.parameters, record.resolved.passes).identity;\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n return [...new Set(values)].sort();\n}\n\nfunction guidText(value: string | Uint8Array): string {\n return typeof value === 'string'\n ? value\n : Array.from(value, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nfunction cookGuidText(value: MaterialTextureReference): string | undefined {\n return typeof value === 'number' ? undefined : guidText(value);\n}\n\nfunction textureValues(\n values: Readonly<Record<string, MaterialValue | null>> | undefined,\n textureFields: ReadonlySet<string>,\n): readonly MaterialTextureValue[] {\n return Object.entries(values ?? {}).flatMap(([name, value]) => {\n if (value === null) return [];\n if (typeof value === 'string') {\n return textureFields.has(name) ? [{ texture: value }] : [];\n }\n return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n 'texture' in value\n ? [value as MaterialTextureValue]\n : [];\n });\n}\n\nexport function collectMaterialCookRefs(material: Partial<MaterialAsset>): MaterialCookRefs {\n const textureFields =\n material.parameters === undefined\n ? new Set<string>(MATERIAL_TEXTURE_SLOTS)\n : new Set(\n material.parameters\n .filter(\n (parameter) => parameter.type === 'texture' || parameter.type === 'texture_cube',\n )\n .map((parameter) => parameter.name),\n );\n const textures = textureValues(material.values, textureFields);\n return {\n parent: material.parent ? [guidText(material.parent)] : [],\n textures: unique(\n textures.flatMap((value) => {\n const guid = cookGuidText(value.texture);\n return guid === undefined ? [] : [guid];\n }),\n ),\n samplers: unique(\n textures.flatMap((value) => {\n if (value.sampler === undefined) return [];\n const guid = cookGuidText(value.sampler);\n return guid === undefined ? [] : [guid];\n }),\n ),\n modules: unique((material.passes ?? []).map((pass) => pass.program.module)),\n };\n}\n\nexport function createMaterialArtifactDigest(bytes: Uint8Array): string {\n return `sha256:${bytesToHex(sha256(bytes))}`;\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return [...value];\n if (Array.isArray(value)) return value.map(jsonValue);\n if (value !== null && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, entry]) => entry !== undefined)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, jsonValue(entry)]),\n );\n }\n return value;\n}\n\nexport function createMaterialCookIdentity(input: MaterialCookIdentityInput): MaterialCookIdentity {\n const cookIdentity = createMaterialArtifactDigest(\n new TextEncoder().encode(\n JSON.stringify(\n jsonValue({\n materialContractDigest: input.materialContractDigest,\n sourceRevision: input.sourceRevision,\n sourceClosureDigest: input.sourceClosureDigest,\n layoutIdentity: input.layoutIdentity,\n programIdentity: input.programIdentity,\n pipelineIdentity: input.pipelineIdentity,\n compilerFingerprint: input.compilerFingerprint,\n wasm: input.wasm,\n artifactDigest: input.artifactDigest,\n }),\n ),\n ),\n );\n return { ...input, cookIdentity };\n}\n\nexport function serializeCookedMaterialRecord(record: CookedMaterialRecord): string {\n return JSON.stringify(jsonValue(record));\n}\n\nexport function serializeMaterialCookReceipt(receipt: MaterialCookReceipt): string {\n return JSON.stringify(jsonValue({ ...receipt, sourceClosure: unique(receipt.sourceClosure) }));\n}\n\nfunction invalid(field: string, actual?: unknown): Result<never, MaterialCookRecordError> {\n return err({\n code: 'material-cook-record-invalid',\n expected: 'a complete material-cook/4 record with layered identity and provenance',\n hint: 're-cook the material and publish its record, artifact, references, and receipt together',\n detail: {\n field,\n ...(actual === undefined ? {} : { actual }),\n action: 'inspect the named field and recook the material generation',\n },\n });\n}\n\nfunction normalizeArtifactBytes(value: unknown): Uint8Array | undefined {\n if (Array.isArray(value)) {\n return value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)\n ? Uint8Array.from(value)\n : undefined;\n }\n if (!ArrayBuffer.isView(value)) return undefined;\n const view = value as ArrayBufferView;\n return new Uint8Array(view.buffer, view.byteOffset, view.byteLength).slice();\n}\n\nconst IDENTITY_FIELDS = [\n 'materialContractDigest',\n 'sourceRevision',\n 'sourceClosureDigest',\n 'layoutIdentity',\n 'programIdentity',\n 'pipelineIdentity',\n 'materialPublicationIdentity',\n 'cookIdentity',\n 'compilerFingerprint',\n 'artifactDigest',\n] as const;\n\nfunction isGeneration(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1;\n}\n\nfunction validateIdentity(value: unknown): Result<MaterialCookIdentity, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt.identity', value);\n const candidate = value as Record<string, unknown>;\n for (const field of IDENTITY_FIELDS) {\n if (typeof candidate[field] !== 'string' || candidate[field].length === 0) {\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n }\n if (candidate.wasm === null || typeof candidate.wasm !== 'object') {\n return invalid('receipt.identity.wasm', candidate.wasm);\n }\n const wasm = candidate.wasm as Record<string, unknown>;\n for (const field of ['sourceContentKey', 'artifactSha256', 'glueSha256']) {\n if (typeof wasm[field] !== 'string' || wasm[field].length === 0) {\n return invalid(`receipt.identity.wasm.${field}`, wasm[field]);\n }\n }\n for (const field of ['valueGeneration', 'dependencyGeneration', 'cookGeneration']) {\n if (!isGeneration(candidate[field]))\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n return ok({\n ...candidate,\n wasm: wasm as unknown as MaterialCookWasmProvenance,\n } as MaterialCookIdentity);\n}\n\nexport function validateMaterialCookReceipt(\n value: unknown,\n expected: MaterialCookIdentityExpectation = {},\n): Result<MaterialCookReceipt, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/4')\n return invalid('receipt.schemaVersion', candidate.schemaVersion);\n const identityResult = validateIdentity(candidate.identity);\n if (!identityResult.ok) return identityResult;\n const identity = identityResult.value;\n if (candidate.derivedInterface === null || typeof candidate.derivedInterface !== 'object') {\n return invalid('receipt.derivedInterface', candidate.derivedInterface);\n }\n const derivedInterface = candidate.derivedInterface as Record<string, unknown>;\n if (derivedInterface.layoutIdentity !== identity.layoutIdentity) {\n return invalid('receipt.derivedInterface.layoutIdentity', derivedInterface.layoutIdentity);\n }\n if (\n derivedInterface.layerPlanIdentity !== undefined &&\n (typeof derivedInterface.layerPlanIdentity !== 'string' ||\n derivedInterface.layerPlanIdentity.length === 0)\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n derivedInterface.layerPlanIdentity,\n );\n }\n for (const field of ['sourceClosure', 'profile', 'compilerVersion']) {\n const fieldValue = candidate[field];\n if (\n (field === 'sourceClosure' && !Array.isArray(fieldValue)) ||\n (field !== 'sourceClosure' && typeof fieldValue !== 'string')\n ) {\n return invalid(`receipt.${field}`, fieldValue);\n }\n }\n const sourceClosure = candidate.sourceClosure;\n if (Array.isArray(sourceClosure) && sourceClosure.some((path) => typeof path !== 'string')) {\n return invalid('receipt.sourceClosure', sourceClosure);\n }\n if (\n expected.layoutIdentity !== undefined &&\n identity.layoutIdentity !== expected.layoutIdentity\n ) {\n return invalid('receipt.identity.layoutIdentity', identity.layoutIdentity);\n }\n if (\n expected.artifactDigest !== undefined &&\n identity.artifactDigest !== expected.artifactDigest\n ) {\n return invalid('receipt.identity.artifactDigest', identity.artifactDigest);\n }\n if (expected.inputDigest !== undefined && identity.cookIdentity !== expected.inputDigest) {\n return invalid('receipt.identity.cookIdentity', identity.cookIdentity);\n }\n return ok({\n schemaVersion: 'material-cook/4',\n sourceClosure: candidate.sourceClosure as string[],\n profile: candidate.profile as string,\n compilerVersion: candidate.compilerVersion as string,\n identity,\n derivedInterface: {\n layoutIdentity: derivedInterface.layoutIdentity as string,\n ...(derivedInterface.layerPlanIdentity === undefined\n ? {}\n : { layerPlanIdentity: derivedInterface.layerPlanIdentity as string }),\n },\n });\n}\n\nexport function validateCookedMaterialRecord(\n value: unknown,\n): Result<CookedMaterialRecord, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('record');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/4')\n return invalid('schemaVersion', candidate.schemaVersion);\n if (typeof candidate.guid !== 'string' || !candidate.guid) return invalid('guid');\n if (candidate.materialGuid !== undefined && typeof candidate.materialGuid !== 'string')\n return invalid('materialGuid');\n if (\n candidate.publicationGeneration !== undefined &&\n !isGeneration(candidate.publicationGeneration)\n )\n return invalid('publicationGeneration', candidate.publicationGeneration);\n if (candidate.specializationKey !== undefined && typeof candidate.specializationKey !== 'string')\n return invalid('specializationKey');\n if ('artifact' in candidate || 'variants' in candidate || 'variantContext' in candidate)\n return invalid('programs', 'legacy single-artifact publication');\n if (candidate.artifactDigest !== undefined && typeof candidate.artifactDigest !== 'string')\n return invalid('artifactDigest');\n if (\n candidate.sourceClosure !== undefined &&\n (!Array.isArray(candidate.sourceClosure) ||\n candidate.sourceClosure.some((path) => typeof path !== 'string'))\n )\n return invalid('sourceClosure');\n if (candidate.parameterContract !== undefined) {\n if (candidate.parameterContract === null || typeof candidate.parameterContract !== 'object')\n return invalid('parameterContract');\n const parameterContract = candidate.parameterContract as Record<string, unknown>;\n if (!Array.isArray(parameterContract.parameters))\n return invalid('parameterContract.parameters');\n if (\n parameterContract.values === null ||\n typeof parameterContract.values !== 'object' ||\n Array.isArray(parameterContract.values)\n )\n return invalid('parameterContract.values');\n }\n if (candidate.resolved === null || typeof candidate.resolved !== 'object')\n return invalid('resolved');\n if (candidate.refs === null || typeof candidate.refs !== 'object') return invalid('refs');\n if (candidate.receipt === null || typeof candidate.receipt !== 'object')\n return invalid('receipt');\n const resolved = candidate.resolved as Record<string, unknown>;\n if (!Array.isArray(resolved.passes)) return invalid('resolved.passes', resolved.passes);\n if (!Array.isArray(resolved.parameters))\n return invalid('resolved.parameters', resolved.parameters);\n if (\n resolved.values === null ||\n typeof resolved.values !== 'object' ||\n Array.isArray(resolved.values)\n )\n return invalid('resolved.values', resolved.values);\n const passes = resolved.passes as MaterialPass[];\n const passNames = new Set<string>();\n for (const [index, pass] of passes.entries()) {\n if (\n pass === null ||\n typeof pass !== 'object' ||\n typeof pass.name !== 'string' ||\n !pass.name ||\n passNames.has(pass.name) ||\n pass.program === null ||\n typeof pass.program !== 'object' ||\n typeof pass.program.module !== 'string'\n )\n return invalid(`resolved.passes[${index}]`);\n passNames.add(pass.name);\n }\n if (!Array.isArray(candidate.programs) || candidate.programs.length === 0)\n return invalid('programs');\n const programs: MaterialCookProgram[] = [];\n const programKeys = new Set<string>();\n const selections = new Set<string>();\n const selectedPasses = new Set<string>();\n for (const [index, entry] of candidate.programs.entries()) {\n const field = `programs[${index}]`;\n if (entry === null || typeof entry !== 'object') return invalid(field);\n const program = entry as Record<string, unknown>;\n if (\n typeof program.specializationKey !== 'string' ||\n !program.specializationKey ||\n programKeys.has(program.specializationKey)\n )\n return invalid(`${field}.specializationKey`);\n programKeys.add(program.specializationKey);\n if (program.artifact === null || typeof program.artifact !== 'object')\n return invalid(`${field}.artifact`);\n const artifact = program.artifact as Record<string, unknown>;\n const bytes = normalizeArtifactBytes(artifact.bytes);\n if (\n artifact.mediaType !== 'text/wgsl' ||\n typeof artifact.path !== 'string' ||\n !artifact.path ||\n typeof artifact.digest !== 'string' ||\n !artifact.digest ||\n bytes === undefined\n )\n return invalid(`${field}.artifact`);\n if (!Array.isArray(program.selections) || program.selections.length === 0)\n return invalid(`${field}.selections`);\n const programSelections: MaterialCookProgram['selections'][number][] = [];\n for (const [selectionIndex, selection] of program.selections.entries()) {\n const selectionField = `${field}.selections[${selectionIndex}]`;\n if (selection === null || typeof selection !== 'object' || !passNames.has(selection.pass))\n return invalid(selectionField);\n const context = validateMaterialCookProgramContext(selection.context);\n if (!context.ok)\n return invalid(\n `${selectionField}.${context.error.detail.field}`,\n context.error.detail.actual,\n );\n const key = JSON.stringify([selection.pass, materialProgramContextKey(context.value)]);\n if (selections.has(key)) return invalid(selectionField, 'ambiguous Pass/context selection');\n selections.add(key);\n selectedPasses.add(selection.pass);\n programSelections.push({ pass: selection.pass, context: context.value });\n }\n programs.push({\n specializationKey: program.specializationKey,\n artifact: { mediaType: 'text/wgsl', path: artifact.path, digest: artifact.digest, bytes },\n selections: programSelections,\n });\n }\n if ([...passNames].some((pass) => !selectedPasses.has(pass)))\n return invalid('programs.selections', 'unpublished Pass');\n const manifestDigest = createMaterialProgramSetDigest(programs, passes);\n const receiptResult = validateMaterialCookReceipt(candidate.receipt, {\n artifactDigest: manifestDigest,\n });\n if (!receiptResult.ok) return receiptResult;\n let expectedLayerPlanIdentity: string | undefined;\n try {\n expectedLayerPlanIdentity = materialLayerPlanIdentity({\n resolved: resolved as unknown as CookedMaterialRecord['resolved'],\n });\n } catch (error) {\n return invalid('resolved.layerPlanIdentity', error instanceof Error ? error.message : error);\n }\n if (\n expectedLayerPlanIdentity !== undefined &&\n receiptResult.value.derivedInterface.layerPlanIdentity !== expectedLayerPlanIdentity\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n receiptResult.value.derivedInterface.layerPlanIdentity,\n );\n }\n if (candidate.artifactDigest !== undefined && candidate.artifactDigest !== manifestDigest)\n return invalid('artifactDigest', candidate.artifactDigest);\n if (\n candidate.publicationGeneration !== undefined &&\n receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration\n )\n return invalid('receipt.identity.cookGeneration', receiptResult.value.identity.cookGeneration);\n return ok({\n ...candidate,\n programs,\n receipt: receiptResult.value,\n } as unknown as CookedMaterialRecord);\n}\n\nexport function projectCookedMaterialRecord(\n record: CookedMaterialRecord,\n): Omit<CookedMaterialRecord, 'guid' | 'authored'> {\n return {\n resolved: record.resolved,\n refs: record.refs,\n programs: record.programs,\n receipt: record.receipt,\n schemaVersion: record.schemaVersion,\n };\n}\n\n/** Canonical context key shared by publication validation and runtime selection. */\nexport function materialProgramContextKey(context: MaterialCookProgramContext): string {\n return JSON.stringify(jsonValue(context));\n}\n\nexport function validateMaterialCookProgramContext(\n value: unknown,\n): Result<MaterialCookProgramContext, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return invalid('context', value);\n const context = value as Record<string, unknown>;\n const fields = {\n backend: ['webgpu', 'webgl2', 'wgpu-native'],\n capability: ['storage-buffer', 'uniform-fallback'],\n pipeline: ['forward', 'deferred'],\n geometry: ['mesh', 'skinned', 'sprite'],\n pass: ['forward', 'shadow', 'depth'],\n profile: ['forgeax-material-wgsl-v1'],\n toolchain: ['naga-oil'],\n instrumentation: ['none', 'validation'],\n };\n for (const field of Object.keys(context)) {\n if (!(field in fields)) return invalid(`context.${field}`, context[field]);\n }\n for (const [field, allowed] of Object.entries(fields)) {\n if (!allowed.includes(context[field] as string))\n return invalid(`context.${field}`, context[field]);\n }\n return ok({ ...context } as unknown as MaterialCookProgramContext);\n}\n\n/** Covers every selection and artifact while excluding transport copies of the bytes. */\nexport function createMaterialProgramSetDigest(\n programs: readonly MaterialCookProgram[],\n passes: readonly MaterialPass[],\n): string {\n const manifest = {\n passes,\n programs: programs\n .map((program) => ({\n specializationKey: program.specializationKey,\n artifact: {\n path: program.artifact.path,\n mediaType: program.artifact.mediaType,\n digest: program.artifact.digest,\n },\n selections: [...program.selections].sort((a, b) =>\n JSON.stringify(jsonValue(a)).localeCompare(JSON.stringify(jsonValue(b))),\n ),\n }))\n .sort((a, b) => a.specializationKey.localeCompare(b.specializationKey)),\n };\n return createMaterialArtifactDigest(\n new TextEncoder().encode(JSON.stringify(jsonValue(manifest))),\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/engine-pack",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -131,7 +131,7 @@
131
131
  }
132
132
  },
133
133
  "dependencies": {
134
- "@forgeax/engine-types": "0.1.25",
134
+ "@forgeax/engine-types": "0.1.27",
135
135
  "@noble/hashes": "^2.2.0",
136
136
  "fast-glob": "^3.3.3",
137
137
  "typescript": "^5.8.3",
@@ -10,7 +10,7 @@ const artifactDigest = 'sha256:output';
10
10
 
11
11
  function receipt(overrides: Record<string, unknown> = {}): MaterialCookReceipt {
12
12
  return {
13
- schemaVersion: 'material-cook/3',
13
+ schemaVersion: 'material-cook/4',
14
14
  sourceClosure: ['b.wgsl', 'a.material.json'],
15
15
  profile: 'webgpu/v1',
16
16
  compilerVersion: 'compiler/1',
@@ -40,9 +40,9 @@ function receipt(overrides: Record<string, unknown> = {}): MaterialCookReceipt {
40
40
  }
41
41
 
42
42
  describe('material cook receipt', () => {
43
- it('requires the v3 identity and provenance tuple', () => {
44
- const v3 = {
45
- schemaVersion: 'material-cook/3',
43
+ it('requires the v4 identity and provenance tuple', () => {
44
+ const v4 = {
45
+ schemaVersion: 'material-cook/4',
46
46
  sourceClosure: ['materials/mat.material.json', 'shaders/pbr.wgsl'],
47
47
  profile: 'webgpu/v1',
48
48
  compilerVersion: 'compiler/1',
@@ -68,12 +68,12 @@ describe('material cook receipt', () => {
68
68
  },
69
69
  derivedInterface: { layoutIdentity },
70
70
  };
71
- expect(validateMaterialCookReceipt(v3)).toMatchObject({ ok: true, value: v3 });
71
+ expect(validateMaterialCookReceipt(v4)).toMatchObject({ ok: true, value: v4 });
72
72
  expect(validateMaterialCookReceipt(receipt())).toMatchObject({ ok: true });
73
73
  expect(
74
74
  validateMaterialCookReceipt({
75
- ...v3,
76
- identity: { ...v3.identity, compilerFingerprint: undefined },
75
+ ...v4,
76
+ identity: { ...v4.identity, compilerFingerprint: undefined },
77
77
  }),
78
78
  ).toMatchObject({
79
79
  ok: false,
@@ -81,14 +81,14 @@ describe('material cook receipt', () => {
81
81
  });
82
82
  });
83
83
 
84
- it('serializes a material-cook/3 receipt stably for equivalent cooks', () => {
84
+ it('serializes a material-cook/4 receipt stably for equivalent cooks', () => {
85
85
  const first = serializeMaterialCookReceipt(receipt());
86
86
  const second = serializeMaterialCookReceipt(
87
87
  receipt({ sourceClosure: ['a.material.json', 'b.wgsl'] }),
88
88
  );
89
89
  expect(first).toBe(second);
90
90
  expect(JSON.parse(first)).toMatchObject({
91
- schemaVersion: 'material-cook/3',
91
+ schemaVersion: 'material-cook/4',
92
92
  identity: { layoutIdentity },
93
93
  derivedInterface: { layoutIdentity },
94
94
  });