@forgeax/engine-pack 0.1.6 → 0.1.19

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.
Files changed (37) hide show
  1. package/README.md +12 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/build.d.ts +1 -1
  4. package/dist/build.d.ts.map +1 -1
  5. package/dist/build.mjs +100 -51
  6. package/dist/build.mjs.map +1 -1
  7. package/dist/catalog-builder.d.ts +12 -0
  8. package/dist/catalog-builder.d.ts.map +1 -1
  9. package/dist/cli-asset.mjs +1 -1
  10. package/dist/cli-asset.mjs.map +1 -1
  11. package/dist/evidence/material-cook.d.ts +28 -6
  12. package/dist/evidence/material-cook.d.ts.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.mjs +97 -42
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/material-cook.d.ts +1 -1
  18. package/dist/material-cook.d.ts.map +1 -1
  19. package/dist/material-cook.mjs +96 -41
  20. package/dist/material-cook.mjs.map +1 -1
  21. package/dist/scanner.mjs +1 -1
  22. package/dist/scanner.mjs.map +1 -1
  23. package/dist/scriptable-pack-node.d.ts.map +1 -1
  24. package/dist/scriptable-pack-node.mjs +1 -1
  25. package/dist/scriptable-pack-node.mjs.map +1 -1
  26. package/package.json +3 -3
  27. package/src/__tests__/material-cook-dependencies.unit.test.ts +111 -0
  28. package/src/__tests__/material-cook-receipt.unit.test.ts +77 -20
  29. package/src/__tests__/material-cook-schema.unit.test.ts +64 -10
  30. package/src/__tests__/pack-v2-fixture-migration.test.ts +24 -1
  31. package/src/build.ts +1 -0
  32. package/src/catalog-builder.ts +42 -5
  33. package/src/evidence/material-cook.ts +133 -54
  34. package/src/index.ts +4 -0
  35. package/src/material-cook.ts +2 -0
  36. package/src/schema/material-cook.schema.json +48 -8
  37. package/src/scriptable-pack-node.ts +4 -1
@@ -1,2 +1,2 @@
1
- export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, type MaterialCookArtifact, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, } from './evidence/material-cook.js';
1
+ export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, type MaterialCookArtifact, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, type MaterialCookWasmProvenance, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, } 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,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,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,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,6BAA6B,CAAC"}
@@ -57,83 +57,138 @@ function jsonValue(value) {
57
57
  }
58
58
  return value;
59
59
  }
60
+ function createMaterialCookIdentity(input) {
61
+ const cookIdentity = createMaterialArtifactDigest(
62
+ new TextEncoder().encode(
63
+ JSON.stringify(
64
+ jsonValue({
65
+ materialContractDigest: input.materialContractDigest,
66
+ sourceRevision: input.sourceRevision,
67
+ sourceClosureDigest: input.sourceClosureDigest,
68
+ layoutIdentity: input.layoutIdentity,
69
+ programIdentity: input.programIdentity,
70
+ pipelineIdentity: input.pipelineIdentity,
71
+ compilerFingerprint: input.compilerFingerprint,
72
+ wasm: input.wasm,
73
+ artifactDigest: input.artifactDigest
74
+ })
75
+ )
76
+ )
77
+ );
78
+ return { ...input, cookIdentity };
79
+ }
60
80
  function serializeCookedMaterialRecord(record) {
61
81
  return JSON.stringify(jsonValue(record));
62
82
  }
63
83
  function serializeMaterialCookReceipt(receipt) {
64
84
  return JSON.stringify(jsonValue({ ...receipt, sourceClosure: unique(receipt.sourceClosure) }));
65
85
  }
66
- function invalid(field) {
86
+ function invalid(field, actual) {
67
87
  return err({
68
88
  code: "material-cook-record-invalid",
69
- expected: "a complete material-cook/2 record with derived layout identity",
89
+ expected: "a complete material-cook/3 record with layered identity and provenance",
70
90
  hint: "re-cook the material and publish its record, artifact, references, and receipt together",
71
- detail: { field }
91
+ detail: {
92
+ field,
93
+ ...actual === void 0 ? {} : { actual },
94
+ action: "inspect the named field and recook the material generation"
95
+ }
96
+ });
97
+ }
98
+ var IDENTITY_FIELDS = [
99
+ "materialContractDigest",
100
+ "sourceRevision",
101
+ "sourceClosureDigest",
102
+ "layoutIdentity",
103
+ "programIdentity",
104
+ "pipelineIdentity",
105
+ "materialPublicationIdentity",
106
+ "cookIdentity",
107
+ "compilerFingerprint",
108
+ "artifactDigest"
109
+ ];
110
+ function isGeneration(value) {
111
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
112
+ }
113
+ function validateIdentity(value) {
114
+ if (value === null || typeof value !== "object") return invalid("receipt.identity", value);
115
+ const candidate = value;
116
+ for (const field of IDENTITY_FIELDS) {
117
+ if (typeof candidate[field] !== "string" || candidate[field].length === 0) {
118
+ return invalid(`receipt.identity.${field}`, candidate[field]);
119
+ }
120
+ }
121
+ if (candidate.wasm === null || typeof candidate.wasm !== "object") {
122
+ return invalid("receipt.identity.wasm", candidate.wasm);
123
+ }
124
+ const wasm = candidate.wasm;
125
+ for (const field of ["sourceContentKey", "artifactSha256", "glueSha256"]) {
126
+ if (typeof wasm[field] !== "string" || wasm[field].length === 0) {
127
+ return invalid(`receipt.identity.wasm.${field}`, wasm[field]);
128
+ }
129
+ }
130
+ for (const field of ["valueGeneration", "dependencyGeneration", "cookGeneration"]) {
131
+ if (!isGeneration(candidate[field]))
132
+ return invalid(`receipt.identity.${field}`, candidate[field]);
133
+ }
134
+ return ok({
135
+ ...candidate,
136
+ wasm
72
137
  });
73
138
  }
74
139
  function validateMaterialCookReceipt(value, expected = {}) {
75
140
  if (value === null || typeof value !== "object") return invalid("receipt");
76
141
  const candidate = value;
77
- if (candidate.schemaVersion !== "material-cook/2") return invalid("receipt.schemaVersion");
78
- if (typeof candidate.layoutIdentity !== "string" || candidate.layoutIdentity.length === 0) {
79
- return invalid("receipt.layoutIdentity");
80
- }
142
+ if (candidate.schemaVersion !== "material-cook/3")
143
+ return invalid("receipt.schemaVersion", candidate.schemaVersion);
144
+ const identityResult = validateIdentity(candidate.identity);
145
+ if (!identityResult.ok) return identityResult;
146
+ const identity = identityResult.value;
81
147
  if (candidate.derivedInterface === null || typeof candidate.derivedInterface !== "object") {
82
- return invalid("receipt.derivedInterface");
148
+ return invalid("receipt.derivedInterface", candidate.derivedInterface);
83
149
  }
84
150
  const derivedInterface = candidate.derivedInterface;
85
- if (derivedInterface.layoutIdentity !== candidate.layoutIdentity) {
86
- return invalid("receipt.derivedInterface.layoutIdentity");
151
+ if (derivedInterface.layoutIdentity !== identity.layoutIdentity) {
152
+ return invalid("receipt.derivedInterface.layoutIdentity", derivedInterface.layoutIdentity);
87
153
  }
88
- for (const field of [
89
- "sourceClosure",
90
- "profile",
91
- "compilerVersion",
92
- "inputDigest",
93
- "outputDigest"
94
- ]) {
154
+ for (const field of ["sourceClosure", "profile", "compilerVersion"]) {
95
155
  const fieldValue = candidate[field];
96
156
  if (field === "sourceClosure" && !Array.isArray(fieldValue) || field !== "sourceClosure" && typeof fieldValue !== "string") {
97
- return invalid(`receipt.${field}`);
157
+ return invalid(`receipt.${field}`, fieldValue);
98
158
  }
99
159
  }
100
160
  const sourceClosure = candidate.sourceClosure;
101
161
  if (Array.isArray(sourceClosure) && sourceClosure.some((path) => typeof path !== "string")) {
102
- return invalid("receipt.sourceClosure");
162
+ return invalid("receipt.sourceClosure", sourceClosure);
103
163
  }
104
- if (expected.layoutIdentity !== void 0 && candidate.layoutIdentity !== expected.layoutIdentity) {
105
- return invalid("receipt.layoutIdentity");
164
+ if (expected.layoutIdentity !== void 0 && identity.layoutIdentity !== expected.layoutIdentity) {
165
+ return invalid("receipt.identity.layoutIdentity", identity.layoutIdentity);
106
166
  }
107
- if (expected.artifactDigest !== void 0 && candidate.outputDigest !== expected.artifactDigest) {
108
- return invalid("receipt.outputDigest");
167
+ if (expected.artifactDigest !== void 0 && identity.artifactDigest !== expected.artifactDigest) {
168
+ return invalid("receipt.identity.artifactDigest", identity.artifactDigest);
109
169
  }
110
- if (expected.inputDigest !== void 0 && candidate.inputDigest !== expected.inputDigest) {
111
- return invalid("receipt.inputDigest");
112
- }
113
- if (candidate.publicationGeneration !== void 0 && (typeof candidate.publicationGeneration !== "number" || !Number.isSafeInteger(candidate.publicationGeneration) || candidate.publicationGeneration < 1)) {
114
- return invalid("receipt.publicationGeneration");
170
+ if (expected.inputDigest !== void 0 && identity.cookIdentity !== expected.inputDigest) {
171
+ return invalid("receipt.identity.cookIdentity", identity.cookIdentity);
115
172
  }
116
173
  return ok({
117
- schemaVersion: "material-cook/2",
174
+ schemaVersion: "material-cook/3",
118
175
  sourceClosure: candidate.sourceClosure,
119
176
  profile: candidate.profile,
120
177
  compilerVersion: candidate.compilerVersion,
121
- inputDigest: candidate.inputDigest,
122
- outputDigest: candidate.outputDigest,
123
- layoutIdentity: candidate.layoutIdentity,
124
- derivedInterface: { layoutIdentity: derivedInterface.layoutIdentity },
125
- ...candidate.publicationGeneration === void 0 ? {} : { publicationGeneration: candidate.publicationGeneration }
178
+ identity,
179
+ derivedInterface: { layoutIdentity: derivedInterface.layoutIdentity }
126
180
  });
127
181
  }
128
182
  function validateCookedMaterialRecord(value) {
129
183
  if (value === null || typeof value !== "object") return invalid("record");
130
184
  const candidate = value;
131
- if (candidate.schemaVersion !== "material-cook/2") return invalid("schemaVersion");
185
+ if (candidate.schemaVersion !== "material-cook/3")
186
+ return invalid("schemaVersion", candidate.schemaVersion);
132
187
  if (typeof candidate.guid !== "string" || !candidate.guid) return invalid("guid");
133
188
  if (candidate.materialGuid !== void 0 && typeof candidate.materialGuid !== "string")
134
189
  return invalid("materialGuid");
135
- if (candidate.publicationGeneration !== void 0 && (typeof candidate.publicationGeneration !== "number" || !Number.isSafeInteger(candidate.publicationGeneration) || candidate.publicationGeneration < 1))
136
- return invalid("publicationGeneration");
190
+ if (candidate.publicationGeneration !== void 0 && !isGeneration(candidate.publicationGeneration))
191
+ return invalid("publicationGeneration", candidate.publicationGeneration);
137
192
  if (candidate.specializationKey !== void 0 && typeof candidate.specializationKey !== "string")
138
193
  return invalid("specializationKey");
139
194
  if (candidate.artifactDigest !== void 0 && typeof candidate.artifactDigest !== "string")
@@ -165,9 +220,9 @@ function validateCookedMaterialRecord(value) {
165
220
  });
166
221
  if (!receiptResult.ok) return receiptResult;
167
222
  if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !== artifact.digest)
168
- return invalid("artifactDigest");
169
- if (candidate.publicationGeneration !== void 0 && receiptResult.value.publicationGeneration !== candidate.publicationGeneration)
170
- return invalid("receipt.publicationGeneration");
223
+ return invalid("artifactDigest", candidate.artifactDigest);
224
+ if (candidate.publicationGeneration !== void 0 && receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration)
225
+ return invalid("receipt.identity.cookGeneration", receiptResult.value.identity.cookGeneration);
171
226
  const normalized = {
172
227
  ...candidate,
173
228
  artifact: {
@@ -188,6 +243,6 @@ function projectCookedMaterialRecord(record) {
188
243
  };
189
244
  }
190
245
 
191
- export { collectMaterialCookRefs, createMaterialArtifactDigest, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord };
246
+ export { collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord };
192
247
  //# sourceMappingURL=material-cook.mjs.map
193
248
  //# sourceMappingURL=material-cook.mjs.map
@@ -1 +1 @@
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 { 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\nexport interface MaterialCookReceipt {\n readonly schemaVersion: 'material-cook/2';\n readonly sourceClosure: readonly string[];\n readonly profile: string;\n readonly compilerVersion: string;\n readonly inputDigest: string;\n readonly outputDigest: string;\n readonly layoutIdentity: string;\n readonly derivedInterface: { readonly layoutIdentity: string };\n readonly publicationGeneration?: number;\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/2';\n readonly guid: string;\n readonly authored?: MaterialAsset;\n readonly materialGuid?: string;\n readonly publicationGeneration?: number;\n readonly specializationKey?: string;\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: { readonly field: string };\n}\n\nexport interface MaterialCookIdentityExpectation {\n readonly layoutIdentity?: string;\n readonly artifactDigest?: string;\n readonly inputDigest?: string;\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((parameter) => parameter.type === 'texture')\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 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): Result<never, MaterialCookRecordError> {\n return err({\n code: 'material-cook-record-invalid',\n expected: 'a complete material-cook/2 record with derived layout identity',\n hint: 're-cook the material and publish its record, artifact, references, and receipt together',\n detail: { field },\n });\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/2') return invalid('receipt.schemaVersion');\n if (typeof candidate.layoutIdentity !== 'string' || candidate.layoutIdentity.length === 0) {\n return invalid('receipt.layoutIdentity');\n }\n if (candidate.derivedInterface === null || typeof candidate.derivedInterface !== 'object') {\n return invalid('receipt.derivedInterface');\n }\n const derivedInterface = candidate.derivedInterface as Record<string, unknown>;\n if (derivedInterface.layoutIdentity !== candidate.layoutIdentity) {\n return invalid('receipt.derivedInterface.layoutIdentity');\n }\n for (const field of [\n 'sourceClosure',\n 'profile',\n 'compilerVersion',\n 'inputDigest',\n 'outputDigest',\n ]) {\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}`);\n }\n }\n const sourceClosure = candidate.sourceClosure;\n if (Array.isArray(sourceClosure) && sourceClosure.some((path) => typeof path !== 'string')) {\n return invalid('receipt.sourceClosure');\n }\n if (\n expected.layoutIdentity !== undefined &&\n candidate.layoutIdentity !== expected.layoutIdentity\n ) {\n return invalid('receipt.layoutIdentity');\n }\n if (expected.artifactDigest !== undefined && candidate.outputDigest !== expected.artifactDigest) {\n return invalid('receipt.outputDigest');\n }\n if (expected.inputDigest !== undefined && candidate.inputDigest !== expected.inputDigest) {\n return invalid('receipt.inputDigest');\n }\n if (\n candidate.publicationGeneration !== undefined &&\n (typeof candidate.publicationGeneration !== 'number' ||\n !Number.isSafeInteger(candidate.publicationGeneration) ||\n candidate.publicationGeneration < 1)\n ) {\n return invalid('receipt.publicationGeneration');\n }\n return ok({\n schemaVersion: 'material-cook/2',\n sourceClosure: candidate.sourceClosure as string[],\n profile: candidate.profile as string,\n compilerVersion: candidate.compilerVersion as string,\n inputDigest: candidate.inputDigest as string,\n outputDigest: candidate.outputDigest as string,\n layoutIdentity: candidate.layoutIdentity,\n derivedInterface: { layoutIdentity: derivedInterface.layoutIdentity as string },\n ...(candidate.publicationGeneration === undefined\n ? {}\n : { publicationGeneration: candidate.publicationGeneration as number }),\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/2') return invalid('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 (typeof candidate.publicationGeneration !== 'number' ||\n !Number.isSafeInteger(candidate.publicationGeneration) ||\n candidate.publicationGeneration < 1)\n )\n return invalid('publicationGeneration');\n if (candidate.specializationKey !== undefined && typeof candidate.specializationKey !== 'string')\n return invalid('specializationKey');\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 if (candidate.artifactDigest !== undefined && candidate.artifactDigest !== artifact.digest)\n return invalid('artifactDigest');\n if (\n candidate.publicationGeneration !== undefined &&\n receiptResult.value.publicationGeneration !== candidate.publicationGeneration\n )\n return invalid('receipt.publicationGeneration');\n const normalized = {\n ...candidate,\n artifact: {\n ...artifact,\n bytes: ArrayBuffer.isView(artifact.bytes)\n ? Uint8Array.from(artifact.bytes as Uint8Array)\n : Uint8Array.from(artifact.bytes as number[]),\n },\n receipt: receiptResult.value,\n } 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 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 { 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\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: { readonly layoutIdentity: string };\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 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\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((parameter) => parameter.type === 'texture')\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\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 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: { layoutIdentity: derivedInterface.layoutIdentity as string },\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.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 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: ArrayBuffer.isView(artifact.bytes)\n ? Uint8Array.from(artifact.bytes as Uint8Array)\n : Uint8Array.from(artifact.bytes as number[]),\n },\n receipt: receiptResult.value,\n } 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 receipt: record.receipt,\n schemaVersion: record.schemaVersion,\n };\n}\n"]}
package/dist/scanner.mjs CHANGED
@@ -8319,7 +8319,7 @@ function buildTimeoutFailure(sourcePath, timeoutMs) {
8319
8319
  };
8320
8320
  }
8321
8321
  async function loadScriptablePack(sourcePath, options = {}) {
8322
- const timeoutMs = options.timeoutMs ?? 5e3;
8322
+ const timeoutMs = options.timeoutMs ?? 15e3;
8323
8323
  const buildTimeoutMs = options.buildTimeoutMs ?? 5e3;
8324
8324
  const executor = options.executor ?? new WorkerScriptablePackExecutor();
8325
8325
  let disposeReason;