@plasius/gpu-model-core 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/dist/index.cjs +579 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +192 -1
- package/dist/index.d.ts +192 -1
- package/dist/index.js +575 -217
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,12 +38,16 @@ __export(index_exports, {
|
|
|
38
38
|
GpuModelDiagnosticsError: () => GpuModelDiagnosticsError,
|
|
39
39
|
GpuModelDocumentError: () => GpuModelDocumentError,
|
|
40
40
|
GpuModelResourceGraphError: () => GpuModelResourceGraphError,
|
|
41
|
+
MODEL_REGISTRY_LIMITS: () => MODEL_REGISTRY_LIMITS,
|
|
42
|
+
ModelRegistryError: () => ModelRegistryError,
|
|
41
43
|
assertGpuModelStaticDemoNormalization: () => assertGpuModelStaticDemoNormalization,
|
|
42
44
|
canCreateGpuModelDocument: () => canCreateGpuModelDocument,
|
|
43
45
|
createAndVerifyGpuModelDocument: () => createAndVerifyGpuModelDocument,
|
|
44
46
|
createGpuModelDocument: () => createGpuModelDocument,
|
|
45
47
|
createGpuModelResourceGraph: () => createGpuModelResourceGraph,
|
|
46
48
|
createGpuModelStaticDemoCompilerInput: () => createGpuModelStaticDemoCompilerInput,
|
|
49
|
+
createModelConversionRegistry: () => createModelConversionRegistry,
|
|
50
|
+
createModelResultBase: () => createModelResultBase,
|
|
47
51
|
encodeGpuModelDocumentCanonical: () => encodeGpuModelDocumentCanonical,
|
|
48
52
|
evaluateGpuModelDiagnostics: () => evaluateGpuModelDiagnostics,
|
|
49
53
|
gpuModelResourceKey: () => gpuModelResourceKey,
|
|
@@ -230,9 +234,9 @@ function readRecord(value, path, allowedKeys) {
|
|
|
230
234
|
}
|
|
231
235
|
return value;
|
|
232
236
|
}
|
|
233
|
-
function requireKey(
|
|
234
|
-
if (!Object.hasOwn(
|
|
235
|
-
return
|
|
237
|
+
function requireKey(record4, key, path) {
|
|
238
|
+
if (!Object.hasOwn(record4, key)) return fail("invalid-value", `${path}.${key}`, "required key is missing");
|
|
239
|
+
return record4[key];
|
|
236
240
|
}
|
|
237
241
|
function readArray(value, path, maximum, minimum = 0) {
|
|
238
242
|
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) {
|
|
@@ -311,9 +315,9 @@ function readNumberTuple(value, path, length, minimum, maximum) {
|
|
|
311
315
|
const input = readArray(value, path, length, length);
|
|
312
316
|
return Object.freeze(input.map((entry, index) => readFinite(entry, `${path}[${index}]`, minimum, maximum)));
|
|
313
317
|
}
|
|
314
|
-
function readOptional(
|
|
315
|
-
if (!Object.hasOwn(
|
|
316
|
-
return parser(
|
|
318
|
+
function readOptional(record4, key, parser, path) {
|
|
319
|
+
if (!Object.hasOwn(record4, key)) return void 0;
|
|
320
|
+
return parser(record4[key], `${path}.${key}`);
|
|
317
321
|
}
|
|
318
322
|
function assignOptional(target, key, value) {
|
|
319
323
|
if (value !== void 0) Object.assign(target, { [key]: value });
|
|
@@ -335,17 +339,17 @@ function readMetadataValue(value, path, depth, budget) {
|
|
|
335
339
|
return Object.freeze(input.map((entry, index) => readMetadataValue(entry, `${path}[${index}]`, depth + 1, budget)));
|
|
336
340
|
}
|
|
337
341
|
if (typeof value !== "object" || value === null) return fail("invalid-type", path, "metadata value is not JSON-compatible");
|
|
338
|
-
const
|
|
339
|
-
const prototype = Object.getPrototypeOf(
|
|
342
|
+
const record4 = value;
|
|
343
|
+
const prototype = Object.getPrototypeOf(record4);
|
|
340
344
|
if (prototype !== Object.prototype && prototype !== null) return fail("invalid-type", path, "metadata objects must be plain objects");
|
|
341
|
-
const keys = Reflect.ownKeys(
|
|
345
|
+
const keys = Reflect.ownKeys(record4);
|
|
342
346
|
if (keys.length > GPU_MODEL_DOCUMENT_LIMITS.metadataObjectKeys) return fail("limit-exceeded", path, "metadata object has too many keys");
|
|
343
347
|
const output = {};
|
|
344
348
|
for (const key of keys) {
|
|
345
349
|
if (typeof key !== "string") return fail("unknown-key", path, "metadata symbol keys are not permitted");
|
|
346
350
|
if (PROHIBITED_KEYS.has(key)) return fail("unknown-key", `${path}.${key}`, "prohibited metadata key");
|
|
347
351
|
readString(key, `${path}.[key]`, GPU_MODEL_DOCUMENT_LIMITS.metadataKeyLength, METADATA_KEY);
|
|
348
|
-
const descriptor = Object.getOwnPropertyDescriptor(
|
|
352
|
+
const descriptor = Object.getOwnPropertyDescriptor(record4, key);
|
|
349
353
|
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) return fail("invalid-type", `${path}.${key}`, "metadata properties must be enumerable data properties");
|
|
350
354
|
output[key] = readMetadataValue(descriptor.value, `${path}.${key}`, depth + 1, budget);
|
|
351
355
|
}
|
|
@@ -358,9 +362,9 @@ function readMetadata(value, path, budget) {
|
|
|
358
362
|
}
|
|
359
363
|
function parseCoordinateSystem(value) {
|
|
360
364
|
const path = "$.coordinateSystem";
|
|
361
|
-
const
|
|
365
|
+
const record4 = readRecord(value, path, ["unit", "upAxis", "forwardAxis", "handedness", "winding", "origin"]);
|
|
362
366
|
for (const [key, expected] of Object.entries(CANONICAL_GPU_MODEL_COORDINATE_SYSTEM)) {
|
|
363
|
-
if (requireKey(
|
|
367
|
+
if (requireKey(record4, key, path) !== expected) return fail("invalid-value", `${path}.${key}`, "coordinate system is not canonical");
|
|
364
368
|
}
|
|
365
369
|
return CANONICAL_GPU_MODEL_COORDINATE_SYSTEM;
|
|
366
370
|
}
|
|
@@ -372,19 +376,19 @@ function parseMatrix(value, path, requireAffine = true) {
|
|
|
372
376
|
return matrix;
|
|
373
377
|
}
|
|
374
378
|
function parseBounds(value, path) {
|
|
375
|
-
const
|
|
376
|
-
const min = readNumberTuple(requireKey(
|
|
377
|
-
const max = readNumberTuple(requireKey(
|
|
379
|
+
const record4 = readRecord(value, path, ["min", "max"]);
|
|
380
|
+
const min = readNumberTuple(requireKey(record4, "min", path), `${path}.min`, 3);
|
|
381
|
+
const max = readNumberTuple(requireKey(record4, "max", path), `${path}.max`, 3);
|
|
378
382
|
for (let index = 0; index < 3; index += 1) {
|
|
379
383
|
if (min[index] > max[index]) return fail("invalid-value", path, "bounds min cannot exceed max");
|
|
380
384
|
}
|
|
381
385
|
return { min, max };
|
|
382
386
|
}
|
|
383
387
|
function parseTransformTrs(value, path) {
|
|
384
|
-
const
|
|
385
|
-
const translation = readNumberTuple(requireKey(
|
|
386
|
-
const rotation = readNumberTuple(requireKey(
|
|
387
|
-
const scale = readNumberTuple(requireKey(
|
|
388
|
+
const record4 = readRecord(value, path, ["translation", "rotation", "scale"]);
|
|
389
|
+
const translation = readNumberTuple(requireKey(record4, "translation", path), `${path}.translation`, 3);
|
|
390
|
+
const rotation = readNumberTuple(requireKey(record4, "rotation", path), `${path}.rotation`, 4);
|
|
391
|
+
const scale = readNumberTuple(requireKey(record4, "scale", path), `${path}.scale`, 3);
|
|
388
392
|
const magnitude = Math.hypot(...rotation);
|
|
389
393
|
if (!almostEqual(magnitude, 1, 1e-4)) return fail("invalid-value", `${path}.rotation`, "rotation quaternion must be normalized");
|
|
390
394
|
return { translation, rotation, scale };
|
|
@@ -406,25 +410,25 @@ function intrinsicBlobArrayBuffer(blob) {
|
|
|
406
410
|
return Reflect.apply(blobArrayBuffer, blob, []);
|
|
407
411
|
}
|
|
408
412
|
function parseResourceHeader(value, path) {
|
|
409
|
-
const
|
|
410
|
-
const kind = readEnum(requireKey(
|
|
411
|
-
const mimeType = readString(requireKey(
|
|
413
|
+
const record4 = readRecord(value, path, ["id", "kind", "contentHash", "byteLength", "mimeType", "payload"]);
|
|
414
|
+
const kind = readEnum(requireKey(record4, "kind", path), `${path}.kind`, ["buffer", "image"]);
|
|
415
|
+
const mimeType = readString(requireKey(record4, "mimeType", path), `${path}.mimeType`, 128, MIME_TYPE).toLowerCase();
|
|
412
416
|
if (kind === "image" ? !IMAGE_MIME_TYPES.has(mimeType) : !BUFFER_MIME_TYPES.has(mimeType)) {
|
|
413
417
|
return fail("invalid-value", `${path}.mimeType`, `unsupported ${kind} MIME type`);
|
|
414
418
|
}
|
|
415
|
-
const payload = requireKey(
|
|
419
|
+
const payload = requireKey(record4, "payload", path);
|
|
416
420
|
if (!(payload instanceof Blob)) return fail("invalid-type", `${path}.payload`, "expected an immutable Blob payload");
|
|
417
421
|
if (Object.getPrototypeOf(payload) !== Blob.prototype || Reflect.ownKeys(payload).some((key) => typeof key === "string")) {
|
|
418
422
|
return fail("invalid-type", `${path}.payload`, "expected a native Blob without caller-defined properties");
|
|
419
423
|
}
|
|
420
|
-
const byteLength = readSafeInteger(requireKey(
|
|
424
|
+
const byteLength = readSafeInteger(requireKey(record4, "byteLength", path), `${path}.byteLength`, 1);
|
|
421
425
|
if (intrinsicBlobSize(payload) !== byteLength) return fail("payload-length-mismatch", `${path}.payload`, "payload byte length does not match byteLength");
|
|
422
426
|
const payloadType = intrinsicBlobType(payload);
|
|
423
427
|
if (payloadType && payloadType.toLowerCase() !== mimeType) return fail("invalid-value", `${path}.payload`, "payload MIME type does not match mimeType");
|
|
424
428
|
return {
|
|
425
|
-
id: readId(requireKey(
|
|
429
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
426
430
|
kind,
|
|
427
|
-
contentHash: readSha256(requireKey(
|
|
431
|
+
contentHash: readSha256(requireKey(record4, "contentHash", path), `${path}.contentHash`),
|
|
428
432
|
byteLength,
|
|
429
433
|
mimeType,
|
|
430
434
|
payload
|
|
@@ -433,11 +437,11 @@ function parseResourceHeader(value, path) {
|
|
|
433
437
|
function resolveVerificationLimits(options) {
|
|
434
438
|
const overrides = options?.limits;
|
|
435
439
|
if (overrides === void 0) return GPU_MODEL_RESOURCE_VERIFICATION_LIMITS;
|
|
436
|
-
const
|
|
440
|
+
const record4 = readRecord(overrides, "$.verification.limits", Object.keys(GPU_MODEL_RESOURCE_VERIFICATION_LIMITS));
|
|
437
441
|
const output = { ...GPU_MODEL_RESOURCE_VERIFICATION_LIMITS };
|
|
438
442
|
for (const [key, ceiling] of Object.entries(GPU_MODEL_RESOURCE_VERIFICATION_LIMITS)) {
|
|
439
|
-
if (!Object.hasOwn(
|
|
440
|
-
const value = readSafeInteger(
|
|
443
|
+
if (!Object.hasOwn(record4, key)) continue;
|
|
444
|
+
const value = readSafeInteger(record4[key], `$.verification.limits.${key}`, 1, ceiling);
|
|
441
445
|
Object.assign(output, { [key]: value });
|
|
442
446
|
}
|
|
443
447
|
if (output.maxImageBytes > output.maxResourceBytes) output.maxImageBytes = output.maxResourceBytes;
|
|
@@ -549,13 +553,13 @@ function createVerificationDeadline(timeoutMs, callerSignal, path) {
|
|
|
549
553
|
};
|
|
550
554
|
}
|
|
551
555
|
function parseInspection(value, path) {
|
|
552
|
-
const
|
|
556
|
+
const record4 = readRecord(value, path, ["valid", "detectedMimeType", "width", "height"]);
|
|
553
557
|
const output = {
|
|
554
|
-
valid: readBoolean(requireKey(
|
|
555
|
-
detectedMimeType: readString(requireKey(
|
|
558
|
+
valid: readBoolean(requireKey(record4, "valid", path), `${path}.valid`),
|
|
559
|
+
detectedMimeType: readString(requireKey(record4, "detectedMimeType", path), `${path}.detectedMimeType`, 128, MIME_TYPE).toLowerCase()
|
|
556
560
|
};
|
|
557
|
-
assignOptional(output, "width", readOptional(
|
|
558
|
-
assignOptional(output, "height", readOptional(
|
|
561
|
+
assignOptional(output, "width", readOptional(record4, "width", (entry, entryPath) => readSafeInteger(entry, entryPath, 1), path));
|
|
562
|
+
assignOptional(output, "height", readOptional(record4, "height", (entry, entryPath) => readSafeInteger(entry, entryPath, 1), path));
|
|
559
563
|
return output;
|
|
560
564
|
}
|
|
561
565
|
function bytesStartWith(bytes, signature) {
|
|
@@ -670,62 +674,62 @@ async function verifyGpuModelResource(value, port, options) {
|
|
|
670
674
|
}
|
|
671
675
|
}
|
|
672
676
|
function parseNode(value, path, budget) {
|
|
673
|
-
const
|
|
674
|
-
const children = Object.freeze(readArray(requireKey(
|
|
677
|
+
const record4 = readRecord(value, path, ["id", "name", "children", "meshId", "skinId", "localMatrix", "metadata"]);
|
|
678
|
+
const children = Object.freeze(readArray(requireKey(record4, "children", path), `${path}.children`, GPU_MODEL_DOCUMENT_LIMITS.nodes).map((entry, index) => readId(entry, `${path}.children[${index}]`)));
|
|
675
679
|
consumeBudget(budget, "sceneEdges", children.length, GPU_MODEL_DOCUMENT_LIMITS.sceneEdges, path, "scene edge");
|
|
676
680
|
ensureUnique(children, `${path}.children`, "duplicate child node");
|
|
677
681
|
const output = {
|
|
678
|
-
id: readId(requireKey(
|
|
682
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
679
683
|
children,
|
|
680
|
-
localMatrix: parseMatrix(requireKey(
|
|
684
|
+
localMatrix: parseMatrix(requireKey(record4, "localMatrix", path), `${path}.localMatrix`)
|
|
681
685
|
};
|
|
682
|
-
assignOptional(output, "name", readOptional(
|
|
683
|
-
assignOptional(output, "meshId", readOptional(
|
|
684
|
-
assignOptional(output, "skinId", readOptional(
|
|
685
|
-
assignOptional(output, "metadata", readOptional(
|
|
686
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
687
|
+
assignOptional(output, "meshId", readOptional(record4, "meshId", readId, path));
|
|
688
|
+
assignOptional(output, "skinId", readOptional(record4, "skinId", readId, path));
|
|
689
|
+
assignOptional(output, "metadata", readOptional(record4, "metadata", (entry, entryPath) => readMetadata(entry, entryPath, budget), path));
|
|
686
690
|
return output;
|
|
687
691
|
}
|
|
688
692
|
function parseAccessor(value, path, budget) {
|
|
689
|
-
const
|
|
690
|
-
const componentType = readEnum(requireKey(
|
|
691
|
-
const elementType = readEnum(requireKey(
|
|
692
|
-
const normalized = readOptional(
|
|
693
|
+
const record4 = readRecord(value, path, ["id", "resourceId", "byteOffset", "byteStride", "count", "componentType", "elementType", "normalized", "min", "max"]);
|
|
694
|
+
const componentType = readEnum(requireKey(record4, "componentType", path), `${path}.componentType`, ["i8", "u8", "i16", "u16", "u32", "f32"]);
|
|
695
|
+
const elementType = readEnum(requireKey(record4, "elementType", path), `${path}.elementType`, ["scalar", "vec2", "vec3", "vec4", "mat2", "mat3", "mat4"]);
|
|
696
|
+
const normalized = readOptional(record4, "normalized", readBoolean, path);
|
|
693
697
|
if (normalized === true && componentType === "f32") return fail("invalid-value", `${path}.normalized`, "floating-point accessors cannot be normalized");
|
|
694
698
|
if (elementType.startsWith("mat") && componentType !== "f32") return fail("invalid-value", `${path}.componentType`, "matrix accessors must use f32 components");
|
|
695
699
|
const expectedComponents = ELEMENT_COMPONENTS[elementType];
|
|
696
|
-
const min = readOptional(
|
|
697
|
-
const max = readOptional(
|
|
700
|
+
const min = readOptional(record4, "min", (entry, entryPath) => readNumberTuple(entry, entryPath, expectedComponents), path);
|
|
701
|
+
const max = readOptional(record4, "max", (entry, entryPath) => readNumberTuple(entry, entryPath, expectedComponents), path);
|
|
698
702
|
if (min === void 0 !== (max === void 0)) return fail("invalid-value", path, "accessor min and max must be supplied together");
|
|
699
703
|
if (min && max) {
|
|
700
|
-
const [componentMinimum, componentMaximum,
|
|
704
|
+
const [componentMinimum, componentMaximum, integer2] = COMPONENT_RANGES[componentType];
|
|
701
705
|
for (let index = 0; index < expectedComponents; index += 1) {
|
|
702
706
|
const minimum = min[index];
|
|
703
707
|
const maximum = max[index];
|
|
704
708
|
if (minimum > maximum) return fail("invalid-value", path, "accessor min cannot exceed max");
|
|
705
|
-
if (minimum < componentMinimum || maximum > componentMaximum ||
|
|
709
|
+
if (minimum < componentMinimum || maximum > componentMaximum || integer2 && (!Number.isInteger(minimum) || !Number.isInteger(maximum))) {
|
|
706
710
|
return fail("invalid-value", path, "accessor bounds are outside the component representation");
|
|
707
711
|
}
|
|
708
712
|
}
|
|
709
713
|
}
|
|
710
|
-
const count = readSafeInteger(requireKey(
|
|
714
|
+
const count = readSafeInteger(requireKey(record4, "count", path), `${path}.count`, 1, GPU_MODEL_DOCUMENT_LIMITS.weightVertices);
|
|
711
715
|
consumeBudget(budget, "accessorElements", count * expectedComponents, GPU_MODEL_DOCUMENT_LIMITS.accessorElements, path, "accessor element component");
|
|
712
716
|
const output = {
|
|
713
|
-
id: readId(requireKey(
|
|
714
|
-
resourceId: readId(requireKey(
|
|
715
|
-
byteOffset: readSafeInteger(requireKey(
|
|
717
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
718
|
+
resourceId: readId(requireKey(record4, "resourceId", path), `${path}.resourceId`),
|
|
719
|
+
byteOffset: readSafeInteger(requireKey(record4, "byteOffset", path), `${path}.byteOffset`),
|
|
716
720
|
count,
|
|
717
721
|
componentType,
|
|
718
722
|
elementType
|
|
719
723
|
};
|
|
720
|
-
assignOptional(output, "byteStride", readOptional(
|
|
724
|
+
assignOptional(output, "byteStride", readOptional(record4, "byteStride", (entry, entryPath) => readSafeInteger(entry, entryPath, 1, 2048), path));
|
|
721
725
|
assignOptional(output, "normalized", normalized);
|
|
722
726
|
assignOptional(output, "min", min);
|
|
723
727
|
assignOptional(output, "max", max);
|
|
724
728
|
return output;
|
|
725
729
|
}
|
|
726
730
|
function parsePrimitive(value, path, budget) {
|
|
727
|
-
const
|
|
728
|
-
const attributesInput = readArray(requireKey(
|
|
731
|
+
const record4 = readRecord(value, path, ["id", "topology", "attributes", "indicesAccessorId", "materialId", "metadata"]);
|
|
732
|
+
const attributesInput = readArray(requireKey(record4, "attributes", path), `${path}.attributes`, 64, 1);
|
|
729
733
|
consumeBudget(budget, "primitiveAttributes", attributesInput.length, GPU_MODEL_DOCUMENT_LIMITS.primitiveAttributes, path, "primitive attribute");
|
|
730
734
|
const attributes = Object.freeze(attributesInput.map((entry, index) => {
|
|
731
735
|
const entryPath = `${path}.attributes[${index}]`;
|
|
@@ -738,53 +742,53 @@ function parsePrimitive(value, path, budget) {
|
|
|
738
742
|
ensureUnique(attributes.map(({ semantic }) => semantic), `${path}.attributes`, "duplicate attribute semantic");
|
|
739
743
|
if (!attributes.some(({ semantic }) => semantic === "POSITION")) return fail("invalid-value", `${path}.attributes`, "primitive requires POSITION");
|
|
740
744
|
const output = {
|
|
741
|
-
id: readId(requireKey(
|
|
742
|
-
topology: readEnum(requireKey(
|
|
745
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
746
|
+
topology: readEnum(requireKey(record4, "topology", path), `${path}.topology`, ["points", "lines", "line-strip", "triangles", "triangle-strip"]),
|
|
743
747
|
attributes
|
|
744
748
|
};
|
|
745
|
-
assignOptional(output, "indicesAccessorId", readOptional(
|
|
746
|
-
assignOptional(output, "materialId", readOptional(
|
|
747
|
-
assignOptional(output, "metadata", readOptional(
|
|
749
|
+
assignOptional(output, "indicesAccessorId", readOptional(record4, "indicesAccessorId", readId, path));
|
|
750
|
+
assignOptional(output, "materialId", readOptional(record4, "materialId", readId, path));
|
|
751
|
+
assignOptional(output, "metadata", readOptional(record4, "metadata", (entry, entryPath) => readMetadata(entry, entryPath, budget), path));
|
|
748
752
|
return output;
|
|
749
753
|
}
|
|
750
754
|
function parseMesh(value, path, budget) {
|
|
751
|
-
const
|
|
752
|
-
const input = readArray(requireKey(
|
|
755
|
+
const record4 = readRecord(value, path, ["id", "name", "primitives", "metadata"]);
|
|
756
|
+
const input = readArray(requireKey(record4, "primitives", path), `${path}.primitives`, GPU_MODEL_DOCUMENT_LIMITS.primitives, 1);
|
|
753
757
|
consumeBudget(budget, "primitives", input.length, GPU_MODEL_DOCUMENT_LIMITS.primitives, path, "primitive");
|
|
754
758
|
const output = {
|
|
755
|
-
id: readId(requireKey(
|
|
759
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
756
760
|
primitives: Object.freeze(input.map((entry, index) => parsePrimitive(entry, `${path}.primitives[${index}]`, budget)))
|
|
757
761
|
};
|
|
758
|
-
assignOptional(output, "name", readOptional(
|
|
759
|
-
assignOptional(output, "metadata", readOptional(
|
|
762
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
763
|
+
assignOptional(output, "metadata", readOptional(record4, "metadata", (entry, entryPath) => readMetadata(entry, entryPath, budget), path));
|
|
760
764
|
return output;
|
|
761
765
|
}
|
|
762
766
|
function parseTextureTransform(value, path) {
|
|
763
|
-
const
|
|
764
|
-
if (Reflect.ownKeys(
|
|
767
|
+
const record4 = readRecord(value, path, ["offset", "rotationRadians", "scale"]);
|
|
768
|
+
if (Reflect.ownKeys(record4).length === 0) return fail("invalid-value", path, "texture transform cannot be empty");
|
|
765
769
|
const output = {};
|
|
766
|
-
assignOptional(output, "offset", readOptional(
|
|
767
|
-
assignOptional(output, "rotationRadians", readOptional(
|
|
768
|
-
assignOptional(output, "scale", readOptional(
|
|
770
|
+
assignOptional(output, "offset", readOptional(record4, "offset", (entry, entryPath) => readNumberTuple(entry, entryPath, 2), path));
|
|
771
|
+
assignOptional(output, "rotationRadians", readOptional(record4, "rotationRadians", readFinite, path));
|
|
772
|
+
assignOptional(output, "scale", readOptional(record4, "scale", (entry, entryPath) => readNumberTuple(entry, entryPath, 2), path));
|
|
769
773
|
return output;
|
|
770
774
|
}
|
|
771
775
|
function parseTextureBinding(value, path) {
|
|
772
|
-
const
|
|
776
|
+
const record4 = readRecord(value, path, ["textureId", "samplerId", "texCoordSet", "transform", "colorSpace", "intendedUsage"]);
|
|
773
777
|
const output = {
|
|
774
|
-
textureId: readId(requireKey(
|
|
775
|
-
colorSpace: readEnum(requireKey(
|
|
776
|
-
intendedUsage: readEnum(requireKey(
|
|
778
|
+
textureId: readId(requireKey(record4, "textureId", path), `${path}.textureId`),
|
|
779
|
+
colorSpace: readEnum(requireKey(record4, "colorSpace", path), `${path}.colorSpace`, ["srgb", "linear", "normal-map", "data"]),
|
|
780
|
+
intendedUsage: readEnum(requireKey(record4, "intendedUsage", path), `${path}.intendedUsage`, TEXTURE_USAGES)
|
|
777
781
|
};
|
|
778
|
-
assignOptional(output, "samplerId", readOptional(
|
|
779
|
-
assignOptional(output, "texCoordSet", readOptional(
|
|
780
|
-
assignOptional(output, "transform", readOptional(
|
|
782
|
+
assignOptional(output, "samplerId", readOptional(record4, "samplerId", readId, path));
|
|
783
|
+
assignOptional(output, "texCoordSet", readOptional(record4, "texCoordSet", (entry, entryPath) => readSafeInteger(entry, entryPath, 0, 7), path));
|
|
784
|
+
assignOptional(output, "transform", readOptional(record4, "transform", parseTextureTransform, path));
|
|
781
785
|
return output;
|
|
782
786
|
}
|
|
783
787
|
function parseMaterialTextures(value, path) {
|
|
784
788
|
const slots = Object.keys(MATERIAL_TEXTURE_SLOTS);
|
|
785
|
-
const
|
|
789
|
+
const record4 = readRecord(value, path, slots);
|
|
786
790
|
const output = {};
|
|
787
|
-
for (const slot of slots) assignOptional(output, slot, readOptional(
|
|
791
|
+
for (const slot of slots) assignOptional(output, slot, readOptional(record4, slot, parseTextureBinding, path));
|
|
788
792
|
return output;
|
|
789
793
|
}
|
|
790
794
|
function parseMaterial(value, path, budget) {
|
|
@@ -810,138 +814,138 @@ function parseMaterial(value, path, budget) {
|
|
|
810
814
|
"extensions",
|
|
811
815
|
"sourceMetadata"
|
|
812
816
|
];
|
|
813
|
-
const
|
|
814
|
-
const alphaMode = readEnum(requireKey(
|
|
815
|
-
const alphaCutoff = readOptional(
|
|
817
|
+
const record4 = readRecord(value, path, keys);
|
|
818
|
+
const alphaMode = readEnum(requireKey(record4, "alphaMode", path), `${path}.alphaMode`, ["opaque", "mask", "blend"]);
|
|
819
|
+
const alphaCutoff = readOptional(record4, "alphaCutoff", (entry, entryPath) => readFinite(entry, entryPath, 0, 1), path);
|
|
816
820
|
if (alphaMode === "mask" && alphaCutoff === void 0) return fail("invalid-value", `${path}.alphaCutoff`, "mask materials require alphaCutoff");
|
|
817
821
|
if (alphaMode !== "mask" && alphaCutoff !== void 0) return fail("invalid-value", `${path}.alphaCutoff`, "alphaCutoff is only valid for mask materials");
|
|
818
822
|
const output = {
|
|
819
|
-
id: readId(requireKey(
|
|
820
|
-
workflow: readEnum(requireKey(
|
|
823
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
824
|
+
workflow: readEnum(requireKey(record4, "workflow", path), `${path}.workflow`, ["metallic-roughness", "specular-glossiness", "unlit", "custom"]),
|
|
821
825
|
alphaMode,
|
|
822
|
-
baseColorFactor: readNumberTuple(requireKey(
|
|
823
|
-
textures: parseMaterialTextures(requireKey(
|
|
824
|
-
extensions: readMetadata(requireKey(
|
|
825
|
-
sourceMetadata: readMetadata(requireKey(
|
|
826
|
+
baseColorFactor: readNumberTuple(requireKey(record4, "baseColorFactor", path), `${path}.baseColorFactor`, 4, 0, 1),
|
|
827
|
+
textures: parseMaterialTextures(requireKey(record4, "textures", path), `${path}.textures`),
|
|
828
|
+
extensions: readMetadata(requireKey(record4, "extensions", path), `${path}.extensions`, budget),
|
|
829
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
826
830
|
};
|
|
827
|
-
assignOptional(output, "name", readOptional(
|
|
831
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
828
832
|
assignOptional(output, "alphaCutoff", alphaCutoff);
|
|
829
|
-
assignOptional(output, "doubleSided", readOptional(
|
|
833
|
+
assignOptional(output, "doubleSided", readOptional(record4, "doubleSided", readBoolean, path));
|
|
830
834
|
for (const key of ["metallicFactor", "roughnessFactor", "transmissionFactor", "clearcoatFactor", "clearcoatRoughnessFactor", "sheenRoughnessFactor", "occlusionStrength"]) {
|
|
831
|
-
assignOptional(output, key, readOptional(
|
|
835
|
+
assignOptional(output, key, readOptional(record4, key, (entry, entryPath) => readFinite(entry, entryPath, 0, 1), path));
|
|
832
836
|
}
|
|
833
|
-
assignOptional(output, "normalScale", readOptional(
|
|
834
|
-
assignOptional(output, "emissiveFactor", readOptional(
|
|
835
|
-
assignOptional(output, "sheenColorFactor", readOptional(
|
|
837
|
+
assignOptional(output, "normalScale", readOptional(record4, "normalScale", readFinite, path));
|
|
838
|
+
assignOptional(output, "emissiveFactor", readOptional(record4, "emissiveFactor", (entry, entryPath) => readNumberTuple(entry, entryPath, 3, 0), path));
|
|
839
|
+
assignOptional(output, "sheenColorFactor", readOptional(record4, "sheenColorFactor", (entry, entryPath) => readNumberTuple(entry, entryPath, 3, 0, 1), path));
|
|
836
840
|
return output;
|
|
837
841
|
}
|
|
838
842
|
function parseTextureSampler(value, path) {
|
|
839
|
-
const
|
|
840
|
-
const output = { id: readId(requireKey(
|
|
841
|
-
assignOptional(output, "wrapS", readOptional(
|
|
842
|
-
assignOptional(output, "wrapT", readOptional(
|
|
843
|
-
assignOptional(output, "minFilter", readOptional(
|
|
844
|
-
assignOptional(output, "magFilter", readOptional(
|
|
845
|
-
assignOptional(output, "mipFilter", readOptional(
|
|
843
|
+
const record4 = readRecord(value, path, ["id", "wrapS", "wrapT", "minFilter", "magFilter", "mipFilter"]);
|
|
844
|
+
const output = { id: readId(requireKey(record4, "id", path), `${path}.id`) };
|
|
845
|
+
assignOptional(output, "wrapS", readOptional(record4, "wrapS", (entry, entryPath) => readEnum(entry, entryPath, ["repeat", "mirrored-repeat", "clamp-to-edge"]), path));
|
|
846
|
+
assignOptional(output, "wrapT", readOptional(record4, "wrapT", (entry, entryPath) => readEnum(entry, entryPath, ["repeat", "mirrored-repeat", "clamp-to-edge"]), path));
|
|
847
|
+
assignOptional(output, "minFilter", readOptional(record4, "minFilter", (entry, entryPath) => readString(entry, entryPath, 128, TOKEN), path));
|
|
848
|
+
assignOptional(output, "magFilter", readOptional(record4, "magFilter", (entry, entryPath) => readString(entry, entryPath, 128, TOKEN), path));
|
|
849
|
+
assignOptional(output, "mipFilter", readOptional(record4, "mipFilter", (entry, entryPath) => readEnum(entry, entryPath, ["nearest", "linear"]), path));
|
|
846
850
|
return output;
|
|
847
851
|
}
|
|
848
852
|
function parseTexture(value, path, budget) {
|
|
849
|
-
const
|
|
850
|
-
const usages = Object.freeze(readArray(requireKey(
|
|
853
|
+
const record4 = readRecord(value, path, ["id", "fileName", "relativePath", "mimeType", "contentHash", "imageResourceId", "byteLength", "intendedUsage", "colorSpace", "sampler", "exportEmbeddingPolicy", "sourceMetadata"]);
|
|
854
|
+
const usages = Object.freeze(readArray(requireKey(record4, "intendedUsage", path), `${path}.intendedUsage`, TEXTURE_USAGES.length, 1).map((entry, index) => readEnum(entry, `${path}.intendedUsage[${index}]`, TEXTURE_USAGES)));
|
|
851
855
|
ensureUnique(usages, `${path}.intendedUsage`, "duplicate intended texture usage");
|
|
852
856
|
const output = {
|
|
853
|
-
id: readId(requireKey(
|
|
854
|
-
contentHash: readSha256(requireKey(
|
|
855
|
-
imageResourceId: readId(requireKey(
|
|
857
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
858
|
+
contentHash: readSha256(requireKey(record4, "contentHash", path), `${path}.contentHash`),
|
|
859
|
+
imageResourceId: readId(requireKey(record4, "imageResourceId", path), `${path}.imageResourceId`),
|
|
856
860
|
intendedUsage: usages,
|
|
857
|
-
colorSpace: readEnum(requireKey(
|
|
858
|
-
exportEmbeddingPolicy: readEnum(requireKey(
|
|
859
|
-
sourceMetadata: readMetadata(requireKey(
|
|
861
|
+
colorSpace: readEnum(requireKey(record4, "colorSpace", path), `${path}.colorSpace`, ["srgb", "linear", "normal-map", "data"]),
|
|
862
|
+
exportEmbeddingPolicy: readEnum(requireKey(record4, "exportEmbeddingPolicy", path), `${path}.exportEmbeddingPolicy`, ["inherit-source", "prefer-embedded", "prefer-external", "forbid-embedding"]),
|
|
863
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
860
864
|
};
|
|
861
|
-
assignOptional(output, "fileName", readOptional(
|
|
862
|
-
assignOptional(output, "relativePath", readOptional(
|
|
863
|
-
assignOptional(output, "mimeType", readOptional(
|
|
864
|
-
assignOptional(output, "byteLength", readOptional(
|
|
865
|
-
assignOptional(output, "sampler", readOptional(
|
|
865
|
+
assignOptional(output, "fileName", readOptional(record4, "fileName", (entry, entryPath) => readString(entry, entryPath, 512, FILE_NAME), path));
|
|
866
|
+
assignOptional(output, "relativePath", readOptional(record4, "relativePath", (entry, entryPath) => readString(entry, entryPath, 2048, RELATIVE_PATH), path));
|
|
867
|
+
assignOptional(output, "mimeType", readOptional(record4, "mimeType", (entry, entryPath) => readString(entry, entryPath, 128, MIME_TYPE).toLowerCase(), path));
|
|
868
|
+
assignOptional(output, "byteLength", readOptional(record4, "byteLength", (entry, entryPath) => readSafeInteger(entry, entryPath, 1), path));
|
|
869
|
+
assignOptional(output, "sampler", readOptional(record4, "sampler", parseTextureSampler, path));
|
|
866
870
|
return output;
|
|
867
871
|
}
|
|
868
872
|
function parseSkeleton(value, path, budget) {
|
|
869
|
-
const
|
|
870
|
-
const jointIds = Object.freeze(readArray(requireKey(
|
|
871
|
-
const rootJointIds = Object.freeze(readArray(requireKey(
|
|
873
|
+
const record4 = readRecord(value, path, ["id", "name", "jointIds", "rootJointIds", "sourceMetadata"]);
|
|
874
|
+
const jointIds = Object.freeze(readArray(requireKey(record4, "jointIds", path), `${path}.jointIds`, GPU_MODEL_DOCUMENT_LIMITS.skinJoints, 1).map((entry, index) => readId(entry, `${path}.jointIds[${index}]`)));
|
|
875
|
+
const rootJointIds = Object.freeze(readArray(requireKey(record4, "rootJointIds", path), `${path}.rootJointIds`, GPU_MODEL_DOCUMENT_LIMITS.skinJoints, 1).map((entry, index) => readId(entry, `${path}.rootJointIds[${index}]`)));
|
|
872
876
|
consumeBudget(budget, "skinJoints", jointIds.length + rootJointIds.length, GPU_MODEL_DOCUMENT_LIMITS.skinJoints, path, "rig joint");
|
|
873
877
|
ensureUnique(jointIds, `${path}.jointIds`, "duplicate skeleton joint");
|
|
874
878
|
ensureUnique(rootJointIds, `${path}.rootJointIds`, "duplicate root joint");
|
|
875
879
|
const output = {
|
|
876
|
-
id: readId(requireKey(
|
|
880
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
877
881
|
jointIds,
|
|
878
882
|
rootJointIds,
|
|
879
|
-
sourceMetadata: readMetadata(requireKey(
|
|
883
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
880
884
|
};
|
|
881
|
-
assignOptional(output, "name", readOptional(
|
|
885
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
882
886
|
return output;
|
|
883
887
|
}
|
|
884
888
|
function parseJoint(value, path, budget) {
|
|
885
|
-
const
|
|
889
|
+
const record4 = readRecord(value, path, ["id", "name", "nodeId", "parentJointId", "restLocalTransform", "inverseBindMatrix", "sourceMetadata"]);
|
|
886
890
|
const output = {
|
|
887
|
-
id: readId(requireKey(
|
|
888
|
-
nodeId: readId(requireKey(
|
|
889
|
-
restLocalTransform: parseTransformTrs(requireKey(
|
|
890
|
-
sourceMetadata: readMetadata(requireKey(
|
|
891
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
892
|
+
nodeId: readId(requireKey(record4, "nodeId", path), `${path}.nodeId`),
|
|
893
|
+
restLocalTransform: parseTransformTrs(requireKey(record4, "restLocalTransform", path), `${path}.restLocalTransform`),
|
|
894
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
891
895
|
};
|
|
892
|
-
assignOptional(output, "name", readOptional(
|
|
893
|
-
assignOptional(output, "parentJointId", readOptional(
|
|
894
|
-
assignOptional(output, "inverseBindMatrix", readOptional(
|
|
896
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
897
|
+
assignOptional(output, "parentJointId", readOptional(record4, "parentJointId", readId, path));
|
|
898
|
+
assignOptional(output, "inverseBindMatrix", readOptional(record4, "inverseBindMatrix", parseMatrix, path));
|
|
895
899
|
return output;
|
|
896
900
|
}
|
|
897
|
-
function parseWeightRows(value, path, rows, columns,
|
|
901
|
+
function parseWeightRows(value, path, rows, columns, integer2, budget) {
|
|
898
902
|
const input = readArray(value, path, rows, rows);
|
|
899
903
|
consumeBudget(budget, "weightVertices", input.length, GPU_MODEL_DOCUMENT_LIMITS.weightVertices, path, "weight vertex");
|
|
900
904
|
consumeBudget(budget, "weightInfluences", input.length * columns, GPU_MODEL_DOCUMENT_LIMITS.weightInfluences, path, "weight influence");
|
|
901
905
|
return Object.freeze(input.map((row, rowIndex) => {
|
|
902
|
-
const parsed = readNumberTuple(row, `${path}[${rowIndex}]`, columns, 0,
|
|
903
|
-
if (
|
|
906
|
+
const parsed = readNumberTuple(row, `${path}[${rowIndex}]`, columns, 0, integer2 ? Number.MAX_SAFE_INTEGER : 1);
|
|
907
|
+
if (integer2 && parsed.some((entry) => !Number.isSafeInteger(entry))) return fail("invalid-value", `${path}[${rowIndex}]`, "joint indices must be safe integers");
|
|
904
908
|
return parsed;
|
|
905
909
|
}));
|
|
906
910
|
}
|
|
907
911
|
function parseVertexWeightSet(value, path, budget) {
|
|
908
|
-
const
|
|
909
|
-
const influences = readSafeInteger(requireKey(
|
|
912
|
+
const record4 = readRecord(value, path, ["primitiveId", "influencesPerVertex", "joints", "weights"]);
|
|
913
|
+
const influences = readSafeInteger(requireKey(record4, "influencesPerVertex", path), `${path}.influencesPerVertex`, 1, 32);
|
|
910
914
|
if (influences % 4 !== 0) return fail("invalid-value", `${path}.influencesPerVertex`, "influencesPerVertex must be a multiple of four");
|
|
911
|
-
const jointRows = readArray(requireKey(
|
|
912
|
-
const weightRows = readArray(requireKey(
|
|
915
|
+
const jointRows = readArray(requireKey(record4, "joints", path), `${path}.joints`, GPU_MODEL_DOCUMENT_LIMITS.weightVertices, 1);
|
|
916
|
+
const weightRows = readArray(requireKey(record4, "weights", path), `${path}.weights`, GPU_MODEL_DOCUMENT_LIMITS.weightVertices, 1);
|
|
913
917
|
if (jointRows.length !== weightRows.length) return fail("invalid-value", path, "joint and weight row counts must match");
|
|
914
918
|
return {
|
|
915
|
-
primitiveId: readId(requireKey(
|
|
919
|
+
primitiveId: readId(requireKey(record4, "primitiveId", path), `${path}.primitiveId`),
|
|
916
920
|
influencesPerVertex: influences,
|
|
917
921
|
joints: parseWeightRows(jointRows, `${path}.joints`, jointRows.length, influences, true, budget),
|
|
918
922
|
weights: parseWeightRows(weightRows, `${path}.weights`, weightRows.length, influences, false, budget)
|
|
919
923
|
};
|
|
920
924
|
}
|
|
921
925
|
function parseSkin(value, path, budget) {
|
|
922
|
-
const
|
|
923
|
-
const jointIds = Object.freeze(readArray(requireKey(
|
|
926
|
+
const record4 = readRecord(value, path, ["id", "skeletonId", "jointIds", "inverseBindMatrices", "weightSets", "sourceMetadata"]);
|
|
927
|
+
const jointIds = Object.freeze(readArray(requireKey(record4, "jointIds", path), `${path}.jointIds`, GPU_MODEL_DOCUMENT_LIMITS.skinJoints, 1).map((entry, index) => readId(entry, `${path}.jointIds[${index}]`)));
|
|
924
928
|
consumeBudget(budget, "skinJoints", jointIds.length, GPU_MODEL_DOCUMENT_LIMITS.skinJoints, path, "skin joint");
|
|
925
929
|
ensureUnique(jointIds, `${path}.jointIds`, "duplicate skin joint");
|
|
926
|
-
const inverseInput = readArray(requireKey(
|
|
930
|
+
const inverseInput = readArray(requireKey(record4, "inverseBindMatrices", path), `${path}.inverseBindMatrices`, GPU_MODEL_DOCUMENT_LIMITS.skinJoints, jointIds.length);
|
|
927
931
|
if (inverseInput.length !== jointIds.length) return fail("invalid-value", `${path}.inverseBindMatrices`, "one inverse bind matrix is required per skin joint");
|
|
928
|
-
const weightInput = readArray(requireKey(
|
|
932
|
+
const weightInput = readArray(requireKey(record4, "weightSets", path), `${path}.weightSets`, GPU_MODEL_DOCUMENT_LIMITS.primitives, 1);
|
|
929
933
|
const weightSets = Object.freeze(weightInput.map((entry, index) => parseVertexWeightSet(entry, `${path}.weightSets[${index}]`, budget)));
|
|
930
934
|
ensureUnique(weightSets.map(({ primitiveId }) => primitiveId), `${path}.weightSets`, "duplicate primitive weight set");
|
|
931
935
|
return {
|
|
932
|
-
id: readId(requireKey(
|
|
933
|
-
skeletonId: readId(requireKey(
|
|
936
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
937
|
+
skeletonId: readId(requireKey(record4, "skeletonId", path), `${path}.skeletonId`),
|
|
934
938
|
jointIds,
|
|
935
939
|
inverseBindMatrices: Object.freeze(inverseInput.map((entry, index) => parseMatrix(entry, `${path}.inverseBindMatrices[${index}]`))),
|
|
936
940
|
weightSets,
|
|
937
|
-
sourceMetadata: readMetadata(requireKey(
|
|
941
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
938
942
|
};
|
|
939
943
|
}
|
|
940
944
|
function parseBlendShapeDelta(value, path) {
|
|
941
|
-
const
|
|
942
|
-
const output = { primitiveId: readId(requireKey(
|
|
945
|
+
const record4 = readRecord(value, path, ["primitiveId", "positionAccessorId", "normalAccessorId", "tangentAccessorId"]);
|
|
946
|
+
const output = { primitiveId: readId(requireKey(record4, "primitiveId", path), `${path}.primitiveId`) };
|
|
943
947
|
for (const key of ["positionAccessorId", "normalAccessorId", "tangentAccessorId"]) {
|
|
944
|
-
assignOptional(output, key, readOptional(
|
|
948
|
+
assignOptional(output, key, readOptional(record4, key, readId, path));
|
|
945
949
|
}
|
|
946
950
|
if (!output.positionAccessorId && !output.normalAccessorId && !output.tangentAccessorId) {
|
|
947
951
|
return fail("invalid-value", path, "blend-shape delta requires at least one accessor");
|
|
@@ -949,8 +953,8 @@ function parseBlendShapeDelta(value, path) {
|
|
|
949
953
|
return output;
|
|
950
954
|
}
|
|
951
955
|
function parseBlendShape(value, path, budget) {
|
|
952
|
-
const
|
|
953
|
-
const deltaInput = readArray(requireKey(
|
|
956
|
+
const record4 = readRecord(value, path, ["id", "meshId", "name", "defaultWeight", "deltas", "sourceMetadata"]);
|
|
957
|
+
const deltaInput = readArray(requireKey(record4, "deltas", path), `${path}.deltas`, GPU_MODEL_DOCUMENT_LIMITS.primitives, 1);
|
|
954
958
|
consumeBudget(
|
|
955
959
|
budget,
|
|
956
960
|
"blendShapeDeltas",
|
|
@@ -962,96 +966,96 @@ function parseBlendShape(value, path, budget) {
|
|
|
962
966
|
const deltas = Object.freeze(deltaInput.map((entry, index) => parseBlendShapeDelta(entry, `${path}.deltas[${index}]`)));
|
|
963
967
|
ensureUnique(deltas.map(({ primitiveId }) => primitiveId), `${path}.deltas`, "duplicate blend-shape primitive delta");
|
|
964
968
|
const output = {
|
|
965
|
-
id: readId(requireKey(
|
|
966
|
-
meshId: readId(requireKey(
|
|
969
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
970
|
+
meshId: readId(requireKey(record4, "meshId", path), `${path}.meshId`),
|
|
967
971
|
deltas,
|
|
968
|
-
sourceMetadata: readMetadata(requireKey(
|
|
972
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
969
973
|
};
|
|
970
|
-
assignOptional(output, "name", readOptional(
|
|
971
|
-
assignOptional(output, "defaultWeight", readOptional(
|
|
974
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
975
|
+
assignOptional(output, "defaultWeight", readOptional(record4, "defaultWeight", (entry, entryPath) => readFinite(entry, entryPath, 0, 1), path));
|
|
972
976
|
return output;
|
|
973
977
|
}
|
|
974
978
|
function parseAnimationSampler(value, path, budget) {
|
|
975
|
-
const
|
|
976
|
-
const timesInput = readArray(requireKey(
|
|
977
|
-
const valuesInput = readArray(requireKey(
|
|
979
|
+
const record4 = readRecord(value, path, ["id", "inputAccessorId", "outputAccessorId", "inputTimesSeconds", "outputValues", "interpolation", "sourceMetadata"]);
|
|
980
|
+
const timesInput = readArray(requireKey(record4, "inputTimesSeconds", path), `${path}.inputTimesSeconds`, GPU_MODEL_DOCUMENT_LIMITS.animationValues, 1);
|
|
981
|
+
const valuesInput = readArray(requireKey(record4, "outputValues", path), `${path}.outputValues`, GPU_MODEL_DOCUMENT_LIMITS.animationValues, 1);
|
|
978
982
|
consumeBudget(budget, "animationValues", timesInput.length + valuesInput.length, GPU_MODEL_DOCUMENT_LIMITS.animationValues, path, "animation value");
|
|
979
983
|
const times = Object.freeze(timesInput.map((entry, index) => readFinite(entry, `${path}.inputTimesSeconds[${index}]`, 0)));
|
|
980
984
|
for (let index = 1; index < times.length; index += 1) {
|
|
981
985
|
if (times[index] <= times[index - 1]) return fail("invalid-value", `${path}.inputTimesSeconds`, "animation input times must be strictly increasing");
|
|
982
986
|
}
|
|
983
987
|
return {
|
|
984
|
-
id: readId(requireKey(
|
|
985
|
-
inputAccessorId: readId(requireKey(
|
|
986
|
-
outputAccessorId: readId(requireKey(
|
|
988
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
989
|
+
inputAccessorId: readId(requireKey(record4, "inputAccessorId", path), `${path}.inputAccessorId`),
|
|
990
|
+
outputAccessorId: readId(requireKey(record4, "outputAccessorId", path), `${path}.outputAccessorId`),
|
|
987
991
|
inputTimesSeconds: times,
|
|
988
992
|
outputValues: Object.freeze(valuesInput.map((entry, index) => readFinite(entry, `${path}.outputValues[${index}]`))),
|
|
989
|
-
interpolation: readEnum(requireKey(
|
|
990
|
-
sourceMetadata: readMetadata(requireKey(
|
|
993
|
+
interpolation: readEnum(requireKey(record4, "interpolation", path), `${path}.interpolation`, ["step", "linear", "cubic-spline"]),
|
|
994
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
991
995
|
};
|
|
992
996
|
}
|
|
993
997
|
function parseAnimationChannel(value, path, budget) {
|
|
994
|
-
const
|
|
998
|
+
const record4 = readRecord(value, path, ["id", "samplerId", "targetType", "targetId", "sourceMetadata"]);
|
|
995
999
|
return {
|
|
996
|
-
id: readId(requireKey(
|
|
997
|
-
samplerId: readId(requireKey(
|
|
998
|
-
targetType: readEnum(requireKey(
|
|
999
|
-
targetId: readId(requireKey(
|
|
1000
|
-
sourceMetadata: readMetadata(requireKey(
|
|
1000
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
1001
|
+
samplerId: readId(requireKey(record4, "samplerId", path), `${path}.samplerId`),
|
|
1002
|
+
targetType: readEnum(requireKey(record4, "targetType", path), `${path}.targetType`, ["node-translation", "node-rotation", "node-scale", "weights"]),
|
|
1003
|
+
targetId: readId(requireKey(record4, "targetId", path), `${path}.targetId`),
|
|
1004
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
1001
1005
|
};
|
|
1002
1006
|
}
|
|
1003
1007
|
function parseAnimation(value, path, budget) {
|
|
1004
|
-
const
|
|
1005
|
-
const samplerInput = readArray(requireKey(
|
|
1006
|
-
const channelInput = readArray(requireKey(
|
|
1008
|
+
const record4 = readRecord(value, path, ["id", "name", "durationSeconds", "samplers", "channels", "sourceMetadata"]);
|
|
1009
|
+
const samplerInput = readArray(requireKey(record4, "samplers", path), `${path}.samplers`, GPU_MODEL_DOCUMENT_LIMITS.animationSamplers, 1);
|
|
1010
|
+
const channelInput = readArray(requireKey(record4, "channels", path), `${path}.channels`, GPU_MODEL_DOCUMENT_LIMITS.animationChannels, 1);
|
|
1007
1011
|
consumeBudget(budget, "animationSamplers", samplerInput.length, GPU_MODEL_DOCUMENT_LIMITS.animationSamplers, path, "animation sampler");
|
|
1008
1012
|
consumeBudget(budget, "animationChannels", channelInput.length, GPU_MODEL_DOCUMENT_LIMITS.animationChannels, path, "animation channel");
|
|
1009
1013
|
const output = {
|
|
1010
|
-
id: readId(requireKey(
|
|
1011
|
-
durationSeconds: readFinite(requireKey(
|
|
1014
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
1015
|
+
durationSeconds: readFinite(requireKey(record4, "durationSeconds", path), `${path}.durationSeconds`, 0),
|
|
1012
1016
|
samplers: Object.freeze(samplerInput.map((entry, index) => parseAnimationSampler(entry, `${path}.samplers[${index}]`, budget))),
|
|
1013
1017
|
channels: Object.freeze(channelInput.map((entry, index) => parseAnimationChannel(entry, `${path}.channels[${index}]`, budget))),
|
|
1014
|
-
sourceMetadata: readMetadata(requireKey(
|
|
1018
|
+
sourceMetadata: readMetadata(requireKey(record4, "sourceMetadata", path), `${path}.sourceMetadata`, budget)
|
|
1015
1019
|
};
|
|
1016
|
-
assignOptional(output, "name", readOptional(
|
|
1020
|
+
assignOptional(output, "name", readOptional(record4, "name", (entry, entryPath) => readString(entry, entryPath, GPU_MODEL_DOCUMENT_LIMITS.nameLength), path));
|
|
1017
1021
|
return output;
|
|
1018
1022
|
}
|
|
1019
1023
|
function parseAnalyticGeometry(value, path, budget) {
|
|
1020
|
-
const
|
|
1021
|
-
if (requireKey(
|
|
1024
|
+
const record4 = readRecord(value, path, ["id", "kind", "sourceResourceId", "sourceUnit", "tessellatedMeshId", "metadata"]);
|
|
1025
|
+
if (requireKey(record4, "kind", path) !== "brep-placeholder") return fail("invalid-value", `${path}.kind`, "unsupported analytic geometry kind");
|
|
1022
1026
|
const output = {
|
|
1023
|
-
id: readId(requireKey(
|
|
1027
|
+
id: readId(requireKey(record4, "id", path), `${path}.id`),
|
|
1024
1028
|
kind: "brep-placeholder",
|
|
1025
|
-
sourceResourceId: readId(requireKey(
|
|
1026
|
-
sourceUnit: readEnum(requireKey(
|
|
1029
|
+
sourceResourceId: readId(requireKey(record4, "sourceResourceId", path), `${path}.sourceResourceId`),
|
|
1030
|
+
sourceUnit: readEnum(requireKey(record4, "sourceUnit", path), `${path}.sourceUnit`, ["metre", "millimetre", "centimetre", "inch", "foot", "unitless"])
|
|
1027
1031
|
};
|
|
1028
|
-
assignOptional(output, "tessellatedMeshId", readOptional(
|
|
1029
|
-
assignOptional(output, "metadata", readOptional(
|
|
1032
|
+
assignOptional(output, "tessellatedMeshId", readOptional(record4, "tessellatedMeshId", readId, path));
|
|
1033
|
+
assignOptional(output, "metadata", readOptional(record4, "metadata", (entry, entryPath) => readMetadata(entry, entryPath, budget), path));
|
|
1030
1034
|
return output;
|
|
1031
1035
|
}
|
|
1032
1036
|
function parseProvenance(value, budget) {
|
|
1033
1037
|
const path = "$.provenance";
|
|
1034
|
-
const
|
|
1038
|
+
const record4 = readRecord(value, path, ["sourceFormat", "sourceContentHash", "converterId", "converterVersion", "provider", "sourceIdentifier", "metadata"]);
|
|
1035
1039
|
const output = {
|
|
1036
|
-
sourceFormat: readString(requireKey(
|
|
1037
|
-
sourceContentHash: readSha256(requireKey(
|
|
1038
|
-
converterId: readString(requireKey(
|
|
1039
|
-
converterVersion: readString(requireKey(
|
|
1040
|
+
sourceFormat: readString(requireKey(record4, "sourceFormat", path), `${path}.sourceFormat`, 128, TOKEN),
|
|
1041
|
+
sourceContentHash: readSha256(requireKey(record4, "sourceContentHash", path), `${path}.sourceContentHash`),
|
|
1042
|
+
converterId: readString(requireKey(record4, "converterId", path), `${path}.converterId`, 128, TOKEN),
|
|
1043
|
+
converterVersion: readString(requireKey(record4, "converterVersion", path), `${path}.converterVersion`, 128, TOKEN)
|
|
1040
1044
|
};
|
|
1041
|
-
assignOptional(output, "provider", readOptional(
|
|
1042
|
-
assignOptional(output, "sourceIdentifier", readOptional(
|
|
1043
|
-
assignOptional(output, "metadata", readOptional(
|
|
1045
|
+
assignOptional(output, "provider", readOptional(record4, "provider", (entry, entryPath) => readString(entry, entryPath, 128, TOKEN), path));
|
|
1046
|
+
assignOptional(output, "sourceIdentifier", readOptional(record4, "sourceIdentifier", (entry, entryPath) => readString(entry, entryPath, 2048), path));
|
|
1047
|
+
assignOptional(output, "metadata", readOptional(record4, "metadata", (entry, entryPath) => readMetadata(entry, entryPath, budget), path));
|
|
1044
1048
|
return output;
|
|
1045
1049
|
}
|
|
1046
1050
|
function parseDiagnostic(value, path, budget) {
|
|
1047
|
-
const
|
|
1051
|
+
const record4 = readRecord(value, path, ["severity", "code", "message", "path", "metadata"]);
|
|
1048
1052
|
const output = {
|
|
1049
|
-
severity: readEnum(requireKey(
|
|
1050
|
-
code: readString(requireKey(
|
|
1051
|
-
message: readString(requireKey(
|
|
1053
|
+
severity: readEnum(requireKey(record4, "severity", path), `${path}.severity`, ["info", "warning", "error"]),
|
|
1054
|
+
code: readString(requireKey(record4, "code", path), `${path}.code`, 128, TOKEN),
|
|
1055
|
+
message: readString(requireKey(record4, "message", path), `${path}.message`, GPU_MODEL_DOCUMENT_LIMITS.diagnosticMessageLength)
|
|
1052
1056
|
};
|
|
1053
|
-
assignOptional(output, "path", readOptional(
|
|
1054
|
-
assignOptional(output, "metadata", readOptional(
|
|
1057
|
+
assignOptional(output, "path", readOptional(record4, "path", (entry, entryPath) => readString(entry, entryPath, 512), path));
|
|
1058
|
+
assignOptional(output, "metadata", readOptional(record4, "metadata", (entry, entryPath) => readMetadata(entry, entryPath, budget), path));
|
|
1055
1059
|
return output;
|
|
1056
1060
|
}
|
|
1057
1061
|
function ensureUnique(values, path, detail = "duplicate identity") {
|
|
@@ -1692,11 +1696,11 @@ var DOCUMENT_KEYS = Object.freeze([
|
|
|
1692
1696
|
]);
|
|
1693
1697
|
function parseGpuModelDocument(value) {
|
|
1694
1698
|
const path = "$";
|
|
1695
|
-
const
|
|
1696
|
-
const schemaVersion = requireKey(
|
|
1699
|
+
const record4 = readRecord(value, path, DOCUMENT_KEYS);
|
|
1700
|
+
const schemaVersion = requireKey(record4, "schemaVersion", path);
|
|
1697
1701
|
if (schemaVersion !== GPU_MODEL_DOCUMENT_SCHEMA_VERSION) return fail("invalid-value", "$.schemaVersion", "unsupported schema version");
|
|
1698
1702
|
const parseCollection = (key, maximum, parser, minimum = 0) => {
|
|
1699
|
-
const input = readArray(requireKey(
|
|
1703
|
+
const input = readArray(requireKey(record4, key, path), `$.${key}`, maximum, minimum);
|
|
1700
1704
|
return Object.freeze(input.map((entry, index) => parser(entry, `$.${key}[${index}]`)));
|
|
1701
1705
|
};
|
|
1702
1706
|
const budget = {
|
|
@@ -1717,10 +1721,10 @@ function parseGpuModelDocument(value) {
|
|
|
1717
1721
|
geometryWorldAccessorInstances: 0,
|
|
1718
1722
|
geometryWorldVertices: 0
|
|
1719
1723
|
};
|
|
1720
|
-
const roots = Object.freeze(readArray(requireKey(
|
|
1724
|
+
const roots = Object.freeze(readArray(requireKey(record4, "roots", path), "$.roots", GPU_MODEL_DOCUMENT_LIMITS.roots, 1).map((entry, index) => readId(entry, `$.roots[${index}]`)));
|
|
1721
1725
|
const document = {
|
|
1722
1726
|
schemaVersion,
|
|
1723
|
-
coordinateSystem: parseCoordinateSystem(requireKey(
|
|
1727
|
+
coordinateSystem: parseCoordinateSystem(requireKey(record4, "coordinateSystem", path)),
|
|
1724
1728
|
roots,
|
|
1725
1729
|
nodes: parseCollection("nodes", GPU_MODEL_DOCUMENT_LIMITS.nodes, (entry, entryPath) => parseNode(entry, entryPath, budget), 1),
|
|
1726
1730
|
resources: parseCollection("resources", GPU_MODEL_DOCUMENT_LIMITS.resources, parseVerifiedResource, 1),
|
|
@@ -1734,10 +1738,10 @@ function parseGpuModelDocument(value) {
|
|
|
1734
1738
|
blendShapes: parseCollection("blendShapes", GPU_MODEL_DOCUMENT_LIMITS.blendShapes, (entry, entryPath) => parseBlendShape(entry, entryPath, budget)),
|
|
1735
1739
|
animations: parseCollection("animations", GPU_MODEL_DOCUMENT_LIMITS.animations, (entry, entryPath) => parseAnimation(entry, entryPath, budget)),
|
|
1736
1740
|
analyticGeometry: parseCollection("analyticGeometry", GPU_MODEL_DOCUMENT_LIMITS.analyticGeometry, (entry, entryPath) => parseAnalyticGeometry(entry, entryPath, budget)),
|
|
1737
|
-
bounds: parseBounds(requireKey(
|
|
1738
|
-
provenance: parseProvenance(requireKey(
|
|
1741
|
+
bounds: parseBounds(requireKey(record4, "bounds", path), "$.bounds"),
|
|
1742
|
+
provenance: parseProvenance(requireKey(record4, "provenance", path), budget),
|
|
1739
1743
|
diagnostics: parseCollection("diagnostics", GPU_MODEL_DOCUMENT_LIMITS.diagnostics, (entry, entryPath) => parseDiagnostic(entry, entryPath, budget)),
|
|
1740
|
-
metadata: readMetadata(requireKey(
|
|
1744
|
+
metadata: readMetadata(requireKey(record4, "metadata", path), "$.metadata", budget)
|
|
1741
1745
|
};
|
|
1742
1746
|
if (document.meshes.length === 0) return fail("invalid-value", "$.meshes", "v1 document bounds require at least one canonical mesh");
|
|
1743
1747
|
validateReferences(document, budget);
|
|
@@ -1774,8 +1778,8 @@ async function createAndVerifyGpuModelDocument(value, port, options) {
|
|
|
1774
1778
|
value.resources.forEach((resource, index) => assertVerifiedResourceEvidence(resource, limits, `$.resources[${index}]`));
|
|
1775
1779
|
return value;
|
|
1776
1780
|
}
|
|
1777
|
-
const
|
|
1778
|
-
const resourceInput = readArray(requireKey(
|
|
1781
|
+
const record4 = readRecord(value, "$", DOCUMENT_KEYS);
|
|
1782
|
+
const resourceInput = readArray(requireKey(record4, "resources", "$"), "$.resources", GPU_MODEL_DOCUMENT_LIMITS.resources, 1);
|
|
1779
1783
|
const parsed = resourceInput.map((entry, index) => {
|
|
1780
1784
|
if (typeof entry === "object" && entry !== null && verifiedResources.has(entry) && verifiedResourceBytes.has(entry)) return entry;
|
|
1781
1785
|
return parseResourceHeader(entry, `$.resources[${index}]`);
|
|
@@ -1788,7 +1792,7 @@ async function createAndVerifyGpuModelDocument(value, port, options) {
|
|
|
1788
1792
|
}
|
|
1789
1793
|
const candidate = {};
|
|
1790
1794
|
for (const key of DOCUMENT_KEYS) {
|
|
1791
|
-
if (Object.hasOwn(
|
|
1795
|
+
if (Object.hasOwn(record4, key)) candidate[key] = record4[key];
|
|
1792
1796
|
}
|
|
1793
1797
|
candidate.resources = verified;
|
|
1794
1798
|
return createGpuModelDocument(candidate);
|
|
@@ -1853,11 +1857,11 @@ async function hashGpuModelDocumentCanonical(document) {
|
|
|
1853
1857
|
return Array.from(new Uint8Array(digest), (value) => value.toString(16).padStart(2, "0")).join("");
|
|
1854
1858
|
}
|
|
1855
1859
|
function resolveStaticDemoLimits(options) {
|
|
1856
|
-
const
|
|
1857
|
-
const enabled = readBoolean(requireKey(
|
|
1860
|
+
const record4 = readRecord(options, "$.options", ["pvoxModelsEnabled", "limits"]);
|
|
1861
|
+
const enabled = readBoolean(requireKey(record4, "pvoxModelsEnabled", "$.options"), "$.options.pvoxModelsEnabled");
|
|
1858
1862
|
if (!enabled) return fail("feature-disabled", "$.options.pvoxModelsEnabled", `${GPU_MODEL_STATIC_DEMO_FEATURE_FLAG} is disabled`);
|
|
1859
|
-
if (!Object.hasOwn(
|
|
1860
|
-
const overrides = readRecord(
|
|
1863
|
+
if (!Object.hasOwn(record4, "limits")) return GPU_MODEL_STATIC_DEMO_LIMITS;
|
|
1864
|
+
const overrides = readRecord(record4.limits, "$.options.limits", Object.keys(GPU_MODEL_STATIC_DEMO_LIMITS));
|
|
1861
1865
|
const limits = { ...GPU_MODEL_STATIC_DEMO_LIMITS };
|
|
1862
1866
|
for (const [key, ceiling] of Object.entries(GPU_MODEL_STATIC_DEMO_LIMITS)) {
|
|
1863
1867
|
if (Object.hasOwn(overrides, key)) limits[key] = readSafeInteger(overrides[key], `$.options.limits.${key}`, 1, ceiling);
|
|
@@ -2319,7 +2323,7 @@ function evaluateGpuModelDiagnostics(value) {
|
|
|
2319
2323
|
const diagnostics = [];
|
|
2320
2324
|
const repairs = [];
|
|
2321
2325
|
const losses = [];
|
|
2322
|
-
let
|
|
2326
|
+
let accepted2 = true;
|
|
2323
2327
|
for (const issue of issues) {
|
|
2324
2328
|
const base = { code: issue.code, path: issue.path, message: issue.message };
|
|
2325
2329
|
if (issue.kind === "violation") {
|
|
@@ -2330,20 +2334,20 @@ function evaluateGpuModelDiagnostics(value) {
|
|
|
2330
2334
|
repairs.push(Object.freeze({ ruleId: rule.id, originalValue: issue.originalValue, action: rule.action, severity: rule.severity, affectedPath: issue.path, confidence: rule.confidence }));
|
|
2331
2335
|
diagnostics.push(Object.freeze({ ...base, kind: "repair", severity: rule.severity, ruleId: rule.id }));
|
|
2332
2336
|
} else {
|
|
2333
|
-
|
|
2337
|
+
accepted2 = false;
|
|
2334
2338
|
diagnostics.push(Object.freeze({ ...base, kind: "blocking-error", severity: "error", ruleId: issue.ruleId }));
|
|
2335
2339
|
}
|
|
2336
2340
|
} else if (issue.kind === "unsupported") {
|
|
2337
|
-
|
|
2341
|
+
accepted2 = false;
|
|
2338
2342
|
diagnostics.push(Object.freeze({ ...issue, severity: "error" }));
|
|
2339
2343
|
} else if (issue.kind === "loss") {
|
|
2340
|
-
if (!allowLoss)
|
|
2344
|
+
if (!allowLoss) accepted2 = false;
|
|
2341
2345
|
const loss = Object.freeze({ ...issue, severity: "warning" });
|
|
2342
2346
|
losses.push(loss);
|
|
2343
2347
|
diagnostics.push(loss);
|
|
2344
2348
|
} else diagnostics.push(Object.freeze({ ...issue, severity: "warning" }));
|
|
2345
2349
|
}
|
|
2346
|
-
return Object.freeze({ mode, standard, accepted, diagnostics: Object.freeze(diagnostics), repairs: Object.freeze(repairs), losses: Object.freeze(losses), ...mode === "forensic" ? { rawSource: args.rawSource } : {} });
|
|
2350
|
+
return Object.freeze({ mode, standard, accepted: accepted2, diagnostics: Object.freeze(diagnostics), repairs: Object.freeze(repairs), losses: Object.freeze(losses), ...mode === "forensic" ? { rawSource: args.rawSource } : {} });
|
|
2347
2351
|
}
|
|
2348
2352
|
|
|
2349
2353
|
// src/resource-graph.ts
|
|
@@ -2537,6 +2541,360 @@ function validateDag(nodes) {
|
|
|
2537
2541
|
if (queue.length !== nodes.size) fail3("graph-cycle");
|
|
2538
2542
|
}
|
|
2539
2543
|
|
|
2544
|
+
// src/adapter-registry.ts
|
|
2545
|
+
var MODEL_REGISTRY_LIMITS = Object.freeze({ adapters: 128, concurrent: 8, timeoutMs: 3e4, maxTimeoutMs: 3e5, string: 4096, mapEntries: 64, manifestEntries: 4096, memoryBytes: 64 * 1024 * 1024 });
|
|
2546
|
+
var ModelRegistryError = class extends TypeError {
|
|
2547
|
+
constructor(code) {
|
|
2548
|
+
super(`GPU model registry: ${code}`);
|
|
2549
|
+
this.code = code;
|
|
2550
|
+
this.name = "ModelRegistryError";
|
|
2551
|
+
}
|
|
2552
|
+
code;
|
|
2553
|
+
};
|
|
2554
|
+
function fail4(code = "invalid-input") {
|
|
2555
|
+
throw new ModelRegistryError(code);
|
|
2556
|
+
}
|
|
2557
|
+
var sourceKinds = ["file-path", "url", "blob-storage-url", "blob", "array-buffer", "uint8-array", "stream"];
|
|
2558
|
+
var targetKinds = ["file-path", "blob-storage-url", "blob", "array-buffer", "uint8-array", "stream", "package"];
|
|
2559
|
+
var bases = /* @__PURE__ */ new WeakMap();
|
|
2560
|
+
function createModelResultBase(input) {
|
|
2561
|
+
const report = evaluateGpuModelDiagnostics(input);
|
|
2562
|
+
const value = Object.freeze({ report, diagnostics: report.diagnostics, warnings: Object.freeze(report.diagnostics.filter((d) => d.severity === "warning")), repairs: report.repairs, lossReports: report.losses });
|
|
2563
|
+
bases.set(report, value);
|
|
2564
|
+
return value;
|
|
2565
|
+
}
|
|
2566
|
+
function record3(value, allowed) {
|
|
2567
|
+
if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail4();
|
|
2568
|
+
const keys = Reflect.ownKeys(value);
|
|
2569
|
+
if (keys.length > MODEL_REGISTRY_LIMITS.mapEntries) fail4();
|
|
2570
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
2571
|
+
for (const key of keys) {
|
|
2572
|
+
if (typeof key !== "string" || allowed && !allowed.includes(key)) fail4();
|
|
2573
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
2574
|
+
if (!("value" in descriptor)) fail4();
|
|
2575
|
+
output[key] = descriptor.value;
|
|
2576
|
+
}
|
|
2577
|
+
return output;
|
|
2578
|
+
}
|
|
2579
|
+
function text2(value) {
|
|
2580
|
+
if (typeof value !== "string" || !value.length || value.length > MODEL_REGISTRY_LIMITS.string || Array.from(value).some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)) fail4();
|
|
2581
|
+
return value;
|
|
2582
|
+
}
|
|
2583
|
+
function format(value) {
|
|
2584
|
+
if (typeof value !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(value)) fail4();
|
|
2585
|
+
return value;
|
|
2586
|
+
}
|
|
2587
|
+
function enumeration(value, values) {
|
|
2588
|
+
if (!values.includes(value)) fail4();
|
|
2589
|
+
return value;
|
|
2590
|
+
}
|
|
2591
|
+
function boolean2(value) {
|
|
2592
|
+
if (typeof value !== "boolean") fail4();
|
|
2593
|
+
return value;
|
|
2594
|
+
}
|
|
2595
|
+
function integer(value, max, min = 0) {
|
|
2596
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max) fail4();
|
|
2597
|
+
return value;
|
|
2598
|
+
}
|
|
2599
|
+
function list(value, max) {
|
|
2600
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > max || Reflect.ownKeys(value).length !== value.length + 1) fail4();
|
|
2601
|
+
return Array.from({ length: value.length }, (_, i) => {
|
|
2602
|
+
const d = Object.getOwnPropertyDescriptor(value, String(i));
|
|
2603
|
+
if (!d || !("value" in d)) fail4();
|
|
2604
|
+
return d.value;
|
|
2605
|
+
});
|
|
2606
|
+
}
|
|
2607
|
+
function strings(value) {
|
|
2608
|
+
const input = record3(value);
|
|
2609
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
2610
|
+
for (const [key, entry] of Object.entries(input)) out[text2(key)] = text2(entry);
|
|
2611
|
+
return Object.freeze(out);
|
|
2612
|
+
}
|
|
2613
|
+
function metadata(value) {
|
|
2614
|
+
const v = record3(value, ["formatId", "displayName", "supportedSourceKinds", "supportedTargetKinds", "supportsAnimations", "supportsSkins", "supportsAnalyticGeometry"]);
|
|
2615
|
+
const kinds = (input, allowed) => {
|
|
2616
|
+
const values = list(input, allowed.length).map((k) => enumeration(k, allowed));
|
|
2617
|
+
if (new Set(values).size !== values.length) fail4();
|
|
2618
|
+
return Object.freeze(values);
|
|
2619
|
+
};
|
|
2620
|
+
return Object.freeze({ formatId: format(v.formatId), displayName: text2(v.displayName), supportedSourceKinds: kinds(v.supportedSourceKinds, sourceKinds), supportedTargetKinds: kinds(v.supportedTargetKinds, targetKinds), supportsAnimations: boolean2(v.supportsAnimations), supportsSkins: boolean2(v.supportsSkins), supportsAnalyticGeometry: boolean2(v.supportsAnalyticGeometry) });
|
|
2621
|
+
}
|
|
2622
|
+
function snapshotIO(input, source) {
|
|
2623
|
+
const v = record3(input);
|
|
2624
|
+
const kind = enumeration(v.kind, source ? sourceKinds : targetKinds);
|
|
2625
|
+
const common = source ? ["kind", "fileNameHint", "mimeTypeHint", "provenance"] : ["kind"];
|
|
2626
|
+
const specific = source ? {
|
|
2627
|
+
"file-path": ["path"],
|
|
2628
|
+
url: ["url", "headers"],
|
|
2629
|
+
"blob-storage-url": ["url", "credentialMode"],
|
|
2630
|
+
blob: ["blob"],
|
|
2631
|
+
"array-buffer": ["bytes"],
|
|
2632
|
+
"uint8-array": ["bytes"],
|
|
2633
|
+
stream: ["stream", "byteLengthHint"]
|
|
2634
|
+
} : {
|
|
2635
|
+
"file-path": ["path", "overwrite"],
|
|
2636
|
+
"blob-storage-url": ["url", "overwrite", "contentType", "metadata"],
|
|
2637
|
+
blob: ["mimeType", "fileName"],
|
|
2638
|
+
"array-buffer": [],
|
|
2639
|
+
"uint8-array": [],
|
|
2640
|
+
stream: ["stream", "contentType"],
|
|
2641
|
+
package: ["packageFormat", "destinationHint", "includeSourcePayload"]
|
|
2642
|
+
};
|
|
2643
|
+
if (Object.keys(v).some((k) => ![...common, ...specific[kind]].includes(k))) fail4();
|
|
2644
|
+
const out = { kind };
|
|
2645
|
+
for (const key of ["fileNameHint", "mimeTypeHint", "mimeType", "fileName", "contentType", "destinationHint"]) if (v[key] !== void 0) out[key] = text2(v[key]);
|
|
2646
|
+
for (const key of ["overwrite", "includeSourcePayload"]) if (v[key] !== void 0) out[key] = boolean2(v[key]);
|
|
2647
|
+
for (const key of ["headers", "metadata"]) if (v[key] !== void 0) out[key] = strings(v[key]);
|
|
2648
|
+
if (v.provenance !== void 0) out.provenance = strings(record3(v.provenance, ["sourceId", "sourceSystem", "acquiredAt", "licenseHint"]));
|
|
2649
|
+
if (v.credentialMode !== void 0) out.credentialMode = enumeration(v.credentialMode, ["anonymous", "signed", "runtime-resolved"]);
|
|
2650
|
+
if (v.byteLengthHint !== void 0) out.byteLengthHint = integer(v.byteLengthHint, Number.MAX_SAFE_INTEGER);
|
|
2651
|
+
if (kind === "file-path") out.path = text2(v.path);
|
|
2652
|
+
if (kind === "url" || kind === "blob-storage-url") {
|
|
2653
|
+
const url = text2(v.url);
|
|
2654
|
+
let parsed;
|
|
2655
|
+
try {
|
|
2656
|
+
parsed = new URL(url);
|
|
2657
|
+
} catch {
|
|
2658
|
+
return fail4();
|
|
2659
|
+
}
|
|
2660
|
+
if (!["https:", "http:"].includes(parsed.protocol) || parsed.username || parsed.password) fail4();
|
|
2661
|
+
out.url = url;
|
|
2662
|
+
}
|
|
2663
|
+
if (source && kind === "blob") {
|
|
2664
|
+
if (!(v.blob instanceof Blob)) fail4();
|
|
2665
|
+
integer(v.blob.size, MODEL_REGISTRY_LIMITS.memoryBytes);
|
|
2666
|
+
out.blob = v.blob;
|
|
2667
|
+
}
|
|
2668
|
+
if (source && (kind === "array-buffer" || kind === "uint8-array")) {
|
|
2669
|
+
if (kind === "array-buffer") {
|
|
2670
|
+
if (!(v.bytes instanceof ArrayBuffer)) fail4();
|
|
2671
|
+
integer(v.bytes.byteLength, MODEL_REGISTRY_LIMITS.memoryBytes);
|
|
2672
|
+
out.bytes = v.bytes.slice(0);
|
|
2673
|
+
} else {
|
|
2674
|
+
if (!(v.bytes instanceof Uint8Array) || !(v.bytes.buffer instanceof ArrayBuffer)) fail4();
|
|
2675
|
+
integer(v.bytes.byteLength, MODEL_REGISTRY_LIMITS.memoryBytes);
|
|
2676
|
+
out.bytes = new Uint8Array(v.bytes);
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
if (kind === "stream") {
|
|
2680
|
+
const stream = v.stream;
|
|
2681
|
+
if (!stream || typeof stream !== "object") fail4();
|
|
2682
|
+
if (source ? !(stream instanceof ReadableStream) && typeof stream[Symbol.asyncIterator] !== "function" : !(stream instanceof WritableStream) && !("write" in stream && typeof stream.write === "function" && typeof stream.end === "function")) fail4();
|
|
2683
|
+
out.stream = stream;
|
|
2684
|
+
}
|
|
2685
|
+
if (kind === "package") out.packageFormat = enumeration(v.packageFormat, ["zip", "tar", "directory-manifest"]);
|
|
2686
|
+
return Object.freeze(out);
|
|
2687
|
+
}
|
|
2688
|
+
function manifest(input) {
|
|
2689
|
+
const v = record3(input, ["format", "entries"]);
|
|
2690
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2691
|
+
const paths = /* @__PURE__ */ new Set();
|
|
2692
|
+
const entries = list(v.entries, MODEL_REGISTRY_LIMITS.manifestEntries).map((entry) => {
|
|
2693
|
+
const e = record3(entry, ["id", "role", "path", "contentType"]);
|
|
2694
|
+
const id = text2(e.id);
|
|
2695
|
+
const path = text2(e.path);
|
|
2696
|
+
if (ids.has(id) || paths.has(path.toLowerCase()) || path.split("/").some((s) => !/^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/.test(s) || /[.]$/.test(s) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:[.]|$)/i.test(s))) fail4();
|
|
2697
|
+
ids.add(id);
|
|
2698
|
+
paths.add(path.toLowerCase());
|
|
2699
|
+
return Object.freeze({ id, path, role: enumeration(e.role, ["mesh", "material", "texture", "animation", "auxiliary"]), ...e.contentType !== void 0 ? { contentType: text2(e.contentType) } : {} });
|
|
2700
|
+
});
|
|
2701
|
+
return Object.freeze({ format: enumeration(v.format, ["zip", "tar", "directory-manifest", "inline"]), entries: Object.freeze(entries) });
|
|
2702
|
+
}
|
|
2703
|
+
function reportBase(value, context) {
|
|
2704
|
+
const base = bases.get(value.report);
|
|
2705
|
+
if (!base || base.report.mode !== context.options.mode || ["diagnostics", "warnings", "repairs", "lossReports"].some((k) => value[k] !== base[k])) fail4("invalid-result");
|
|
2706
|
+
return base;
|
|
2707
|
+
}
|
|
2708
|
+
function accepted(report, context) {
|
|
2709
|
+
return report.accepted && (context.options.allowLoss || report.losses.length === 0);
|
|
2710
|
+
}
|
|
2711
|
+
function ledger(stages, ok, payload = {}) {
|
|
2712
|
+
return Object.freeze({ ...payload, accepted: ok, stages: Object.freeze([...stages]), diagnostics: Object.freeze(stages.flatMap((s) => s.report.diagnostics)), warnings: Object.freeze(stages.flatMap((s) => s.report.diagnostics.filter((d) => d.severity === "warning"))), repairs: Object.freeze(stages.flatMap((s) => s.report.repairs)), lossReports: Object.freeze(stages.flatMap((s) => s.report.losses)) });
|
|
2713
|
+
}
|
|
2714
|
+
function createModelConversionRegistry(adapters, limits = {}) {
|
|
2715
|
+
const registry = /* @__PURE__ */ new Map();
|
|
2716
|
+
const maxConcurrent = integer(record3(limits, ["maxConcurrent"]).maxConcurrent ?? MODEL_REGISTRY_LIMITS.concurrent, MODEL_REGISTRY_LIMITS.concurrent, 1);
|
|
2717
|
+
for (const input of list(adapters, MODEL_REGISTRY_LIMITS.adapters)) {
|
|
2718
|
+
let a;
|
|
2719
|
+
try {
|
|
2720
|
+
const v = record3(input, ["metadata", "inspect", "load", "export", "validate"]);
|
|
2721
|
+
const m = metadata(v.metadata);
|
|
2722
|
+
for (const name of ["inspect", "load", "export", "validate"]) if (typeof v[name] !== "function") fail4();
|
|
2723
|
+
const raw = input;
|
|
2724
|
+
a = Object.freeze({ metadata: m, inspect: raw.inspect.bind(raw), load: raw.load.bind(raw), export: raw.export.bind(raw), validate: raw.validate.bind(raw) });
|
|
2725
|
+
} catch {
|
|
2726
|
+
return fail4("invalid-adapter");
|
|
2727
|
+
}
|
|
2728
|
+
if (registry.has(a.metadata.formatId)) fail4("duplicate-format");
|
|
2729
|
+
registry.set(a.metadata.formatId, a);
|
|
2730
|
+
}
|
|
2731
|
+
let active = 0;
|
|
2732
|
+
function lookup(id) {
|
|
2733
|
+
const a = registry.get(format(id));
|
|
2734
|
+
if (!a) fail4("unsupported-format");
|
|
2735
|
+
return a;
|
|
2736
|
+
}
|
|
2737
|
+
function sourceFor(a, input) {
|
|
2738
|
+
const source = snapshotIO(input, true);
|
|
2739
|
+
if (!a.metadata.supportedSourceKinds.includes(source.kind)) fail4("unsupported-source");
|
|
2740
|
+
return source;
|
|
2741
|
+
}
|
|
2742
|
+
function targetFor(a, input) {
|
|
2743
|
+
const target = snapshotIO(input, false);
|
|
2744
|
+
if (!a.metadata.supportedTargetKinds.includes(target.kind)) fail4("unsupported-target");
|
|
2745
|
+
return target;
|
|
2746
|
+
}
|
|
2747
|
+
function check(context) {
|
|
2748
|
+
if (context.options.signal.aborted) fail4("aborted");
|
|
2749
|
+
if (Date.now() >= context.deadline) fail4("deadline-exceeded");
|
|
2750
|
+
}
|
|
2751
|
+
async function run(options, work) {
|
|
2752
|
+
const v = record3(options ?? {}, ["mode", "allowLoss", "signal", "timeoutMs"]);
|
|
2753
|
+
const mode = enumeration(v.mode ?? "strict", ["strict", "tolerant", "forensic"]);
|
|
2754
|
+
const allowLoss = v.allowLoss === void 0 ? false : boolean2(v.allowLoss);
|
|
2755
|
+
const timeoutMs = integer(v.timeoutMs ?? MODEL_REGISTRY_LIMITS.timeoutMs, MODEL_REGISTRY_LIMITS.maxTimeoutMs, 1);
|
|
2756
|
+
if (v.signal !== void 0 && !(v.signal instanceof AbortSignal)) fail4();
|
|
2757
|
+
const parent = v.signal;
|
|
2758
|
+
if (parent?.aborted) fail4("aborted");
|
|
2759
|
+
if (active >= maxConcurrent) fail4("capacity-exceeded");
|
|
2760
|
+
const controller = new AbortController();
|
|
2761
|
+
const context = { options: Object.freeze({ mode, allowLoss, timeoutMs, signal: controller.signal }), deadline: Date.now() + timeoutMs };
|
|
2762
|
+
active++;
|
|
2763
|
+
let timer;
|
|
2764
|
+
let abort;
|
|
2765
|
+
const pending = Promise.resolve().then(() => {
|
|
2766
|
+
check(context);
|
|
2767
|
+
return work(context);
|
|
2768
|
+
}).finally(() => {
|
|
2769
|
+
active--;
|
|
2770
|
+
});
|
|
2771
|
+
const stopped = new Promise((_, reject) => {
|
|
2772
|
+
abort = () => {
|
|
2773
|
+
controller.abort();
|
|
2774
|
+
reject(new ModelRegistryError("aborted"));
|
|
2775
|
+
};
|
|
2776
|
+
parent?.addEventListener("abort", abort, { once: true });
|
|
2777
|
+
timer = setTimeout(() => {
|
|
2778
|
+
controller.abort();
|
|
2779
|
+
reject(new ModelRegistryError("deadline-exceeded"));
|
|
2780
|
+
}, timeoutMs);
|
|
2781
|
+
});
|
|
2782
|
+
try {
|
|
2783
|
+
return await Promise.race([pending, stopped]);
|
|
2784
|
+
} catch (error) {
|
|
2785
|
+
if (error instanceof ModelRegistryError) throw error;
|
|
2786
|
+
return fail4();
|
|
2787
|
+
} finally {
|
|
2788
|
+
clearTimeout(timer);
|
|
2789
|
+
if (abort) parent?.removeEventListener("abort", abort);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
async function invoke(a, operation, context, call, stages) {
|
|
2793
|
+
check(context);
|
|
2794
|
+
let raw;
|
|
2795
|
+
try {
|
|
2796
|
+
raw = await call();
|
|
2797
|
+
} catch {
|
|
2798
|
+
return fail4("adapter-failed");
|
|
2799
|
+
}
|
|
2800
|
+
check(context);
|
|
2801
|
+
try {
|
|
2802
|
+
const v = record3(raw, ["report", "diagnostics", "warnings", "repairs", "lossReports", ...{ inspect: ["detectedFormat", "capabilities"], load: ["document", "resourcePackage"], validate: ["valid"], export: ["target", "resourcePackage", "output"] }[operation]]);
|
|
2803
|
+
const base = reportBase(v, context);
|
|
2804
|
+
const result = { ...v, ...base };
|
|
2805
|
+
if (v.resourcePackage !== void 0) result.resourcePackage = manifest(v.resourcePackage);
|
|
2806
|
+
stages.push(Object.freeze({ formatId: a.metadata.formatId, operation, report: base.report }));
|
|
2807
|
+
return result;
|
|
2808
|
+
} catch {
|
|
2809
|
+
return fail4("invalid-result");
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
async function load(a, source, c, stages) {
|
|
2813
|
+
const v = await invoke(a, "load", c, () => a.load(source, c.options), stages);
|
|
2814
|
+
if (v.document !== void 0 && !isGpuModelDocument(v.document)) fail4("invalid-result");
|
|
2815
|
+
if (accepted(v.report, c) && !isGpuModelDocument(v.document)) fail4("invalid-result");
|
|
2816
|
+
return Object.freeze(v);
|
|
2817
|
+
}
|
|
2818
|
+
async function validate(a, input, c, stages) {
|
|
2819
|
+
const v = await invoke(a, "validate", c, () => a.validate(input, c.options), stages);
|
|
2820
|
+
if (typeof v.valid !== "boolean") fail4("invalid-result");
|
|
2821
|
+
return v.valid && accepted(v.report, c);
|
|
2822
|
+
}
|
|
2823
|
+
async function exportDocument(a, document, target, c, stages) {
|
|
2824
|
+
const issues = [];
|
|
2825
|
+
for (const [supported, present, path] of [[a.metadata.supportsAnimations, document.animations.length, "/animations"], [a.metadata.supportsSkins, document.skins.length + document.skeletons.length + document.joints.length, "/skins"], [a.metadata.supportsAnalyticGeometry, document.analyticGeometry.length, "/analyticGeometry"]]) {
|
|
2826
|
+
if (!supported && present) issues.push({ kind: "loss", code: "TARGET_CAPABILITY_LOSS", path, message: "Target cannot preserve canonical semantics", effect: "dropped" });
|
|
2827
|
+
}
|
|
2828
|
+
const report = evaluateGpuModelDiagnostics({ standard: "gltf-glb", mode: c.options.mode, allowLoss: c.options.allowLoss, issues, ...c.options.mode === "forensic" ? { rawSource: null } : {} });
|
|
2829
|
+
stages.push(Object.freeze({ formatId: a.metadata.formatId, operation: "capabilities", report }));
|
|
2830
|
+
if (!accepted(report, c) || !await validate(a, document, c, stages)) return ledger(stages, false, { document });
|
|
2831
|
+
const v = await invoke(a, "export", c, () => a.export(document, target, c.options), stages);
|
|
2832
|
+
if (v.target !== target.kind) fail4("invalid-result");
|
|
2833
|
+
try {
|
|
2834
|
+
if (v.output !== void 0) {
|
|
2835
|
+
const output = v.output;
|
|
2836
|
+
if (target.kind === "blob" && output instanceof Blob) {
|
|
2837
|
+
integer(output.size, MODEL_REGISTRY_LIMITS.memoryBytes);
|
|
2838
|
+
} else if (target.kind === "array-buffer" && output instanceof ArrayBuffer) {
|
|
2839
|
+
integer(output.byteLength, MODEL_REGISTRY_LIMITS.memoryBytes);
|
|
2840
|
+
v.output = output.slice(0);
|
|
2841
|
+
} else if (target.kind === "uint8-array" && output instanceof Uint8Array && output.buffer instanceof ArrayBuffer) {
|
|
2842
|
+
integer(output.byteLength, MODEL_REGISTRY_LIMITS.memoryBytes);
|
|
2843
|
+
v.output = new Uint8Array(output);
|
|
2844
|
+
} else fail4();
|
|
2845
|
+
}
|
|
2846
|
+
} catch {
|
|
2847
|
+
return fail4("invalid-result");
|
|
2848
|
+
}
|
|
2849
|
+
const exported = Object.freeze(v);
|
|
2850
|
+
return ledger(stages, accepted(exported.report, c), { document, exported, ...exported.resourcePackage ? { resourcePackage: exported.resourcePackage } : {} });
|
|
2851
|
+
}
|
|
2852
|
+
const api = {
|
|
2853
|
+
capabilities: Object.freeze([...registry.values()].map((a) => a.metadata)),
|
|
2854
|
+
inspect: (id, input, options) => run(options, async (c) => {
|
|
2855
|
+
const a = lookup(id);
|
|
2856
|
+
const source = sourceFor(a, input);
|
|
2857
|
+
const stages = [];
|
|
2858
|
+
const v = await invoke(a, "inspect", c, () => a.inspect(source, c.options), stages);
|
|
2859
|
+
try {
|
|
2860
|
+
if (v.detectedFormat !== void 0 && format(v.detectedFormat) !== a.metadata.formatId) fail4();
|
|
2861
|
+
if (JSON.stringify(metadata(v.capabilities)) !== JSON.stringify(a.metadata)) fail4();
|
|
2862
|
+
} catch {
|
|
2863
|
+
return fail4("invalid-result");
|
|
2864
|
+
}
|
|
2865
|
+
return ledger(stages, accepted(v.report, c), { inspection: Object.freeze({ ...v, capabilities: a.metadata }) });
|
|
2866
|
+
}),
|
|
2867
|
+
load: (id, input, options) => run(options, async (c) => {
|
|
2868
|
+
const a = lookup(id);
|
|
2869
|
+
const stages = [];
|
|
2870
|
+
const result = await load(a, sourceFor(a, input), c, stages);
|
|
2871
|
+
return ledger(stages, accepted(result.report, c), { ...result.document ? { document: result.document } : {}, ...result.resourcePackage ? { resourcePackage: result.resourcePackage } : {} });
|
|
2872
|
+
}),
|
|
2873
|
+
validate: (id, input, options) => run(options, async (c) => {
|
|
2874
|
+
const a = lookup(id);
|
|
2875
|
+
const stages = [];
|
|
2876
|
+
return ledger(stages, await validate(a, isGpuModelDocument(input) ? input : sourceFor(a, input), c, stages));
|
|
2877
|
+
}),
|
|
2878
|
+
export: (id, document, input, options) => run(options, async (c) => {
|
|
2879
|
+
const a = lookup(id);
|
|
2880
|
+
if (!isGpuModelDocument(document)) fail4();
|
|
2881
|
+
return exportDocument(a, document, targetFor(a, input), c, []);
|
|
2882
|
+
}),
|
|
2883
|
+
convert: (request, options) => run(options, async (c) => {
|
|
2884
|
+
const v = record3(request, ["sourceFormat", "targetFormat", "source", "target"]);
|
|
2885
|
+
const from = lookup(v.sourceFormat);
|
|
2886
|
+
const to = lookup(v.targetFormat);
|
|
2887
|
+
const source = sourceFor(from, v.source);
|
|
2888
|
+
const target = targetFor(to, v.target);
|
|
2889
|
+
const stages = [];
|
|
2890
|
+
const result = await load(from, source, c, stages);
|
|
2891
|
+
if (!accepted(result.report, c)) return ledger(stages, false, { ...result.resourcePackage ? { resourcePackage: result.resourcePackage } : {} });
|
|
2892
|
+
return exportDocument(to, result.document, target, c, stages);
|
|
2893
|
+
})
|
|
2894
|
+
};
|
|
2895
|
+
return Object.freeze(api);
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2540
2898
|
// src/index.ts
|
|
2541
2899
|
var packageName = "@plasius/gpu-model-core";
|
|
2542
2900
|
var packageBootstrap = Object.freeze({
|
|
@@ -2564,12 +2922,16 @@ var packageBootstrap = Object.freeze({
|
|
|
2564
2922
|
GpuModelDiagnosticsError,
|
|
2565
2923
|
GpuModelDocumentError,
|
|
2566
2924
|
GpuModelResourceGraphError,
|
|
2925
|
+
MODEL_REGISTRY_LIMITS,
|
|
2926
|
+
ModelRegistryError,
|
|
2567
2927
|
assertGpuModelStaticDemoNormalization,
|
|
2568
2928
|
canCreateGpuModelDocument,
|
|
2569
2929
|
createAndVerifyGpuModelDocument,
|
|
2570
2930
|
createGpuModelDocument,
|
|
2571
2931
|
createGpuModelResourceGraph,
|
|
2572
2932
|
createGpuModelStaticDemoCompilerInput,
|
|
2933
|
+
createModelConversionRegistry,
|
|
2934
|
+
createModelResultBase,
|
|
2573
2935
|
encodeGpuModelDocumentCanonical,
|
|
2574
2936
|
evaluateGpuModelDiagnostics,
|
|
2575
2937
|
gpuModelResourceKey,
|