Advance Blender 5.2 web parity through M12-03D
This commit is contained in:
161
web/protocol/asset-catalog-compatibility.ts
Normal file
161
web/protocol/asset-catalog-compatibility.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { parseAssetLibraryManifest } from "./asset-library-io";
|
||||
import { ASSET_CATALOG_SCHEMA, parseAssetCatalogManifestV2 } from "./asset-catalog-v2";
|
||||
import type { ErrorCode } from "./error";
|
||||
|
||||
export const ASSET_CATALOG_COMPATIBILITY_SCHEMA = 1 as const;
|
||||
export type AssetCatalogLegacyOperation = "READ" | "CATALOG_WRITE" | "ASSET_WRITE" | "SAVE";
|
||||
|
||||
export interface AssetCatalogLegacySnapshotIR {
|
||||
revision: number;
|
||||
catalogs: Array<{ catalogId: string; path: string; simpleName: string }>;
|
||||
assets: Array<{ assetId: string; relativeAssetIdentifier: string; idType: string; name: string; catalogId: string | null }>;
|
||||
libraries: Array<{ libraryId: string; name: string; readOnly: boolean }>;
|
||||
}
|
||||
|
||||
export interface AssetCatalogLegacyCompatibilityIR {
|
||||
schemaVersion: typeof ASSET_CATALOG_COMPATIBILITY_SCHEMA;
|
||||
task: "M12-01E";
|
||||
readerSchemaVersion: 1;
|
||||
documentSchemaVersion: number;
|
||||
operation: AssetCatalogLegacyOperation;
|
||||
status: "READY" | "READ_ONLY" | "BLOCKED";
|
||||
code: ErrorCode | null;
|
||||
recoverable: boolean;
|
||||
sourceSha256: string;
|
||||
snapshot: AssetCatalogLegacySnapshotIR | null;
|
||||
nextTask: "M12-01F";
|
||||
}
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
function record(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function stableJSON(value: unknown): string {
|
||||
if (Array.isArray(value)) return `[${value.map(stableJSON).join(",")}]`;
|
||||
if (record(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJSON(value[key])}`).join(",")}}`;
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
async function sha256(value: unknown): Promise<string> {
|
||||
const digest = await crypto.subtle.digest("SHA-256", encoder.encode(stableJSON(value)));
|
||||
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
||||
}
|
||||
|
||||
function operation(value: unknown): AssetCatalogLegacyOperation {
|
||||
if (value !== "READ" && value !== "CATALOG_WRITE" && value !== "ASSET_WRITE" && value !== "SAVE") {
|
||||
throw new Error("ASSET_MANIFEST_INVALID: legacy reader operation is invalid");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export async function inspectAssetCatalogForLegacyReader(
|
||||
value: unknown,
|
||||
operationValue: unknown,
|
||||
): Promise<AssetCatalogLegacyCompatibilityIR> {
|
||||
const requestedOperation = operation(operationValue);
|
||||
const sourceSha256 = await sha256(value);
|
||||
if (!record(value) || typeof value.schemaVersion !== "number" || !Number.isSafeInteger(value.schemaVersion)) {
|
||||
return {
|
||||
schemaVersion: ASSET_CATALOG_COMPATIBILITY_SCHEMA,
|
||||
task: "M12-01E",
|
||||
readerSchemaVersion: 1,
|
||||
documentSchemaVersion: 0,
|
||||
operation: requestedOperation,
|
||||
status: "BLOCKED",
|
||||
code: "PROTOCOL_MISMATCH",
|
||||
recoverable: false,
|
||||
sourceSha256,
|
||||
snapshot: null,
|
||||
nextTask: "M12-01F",
|
||||
};
|
||||
}
|
||||
if (value.schemaVersion === 1) {
|
||||
try {
|
||||
parseAssetLibraryManifest(value);
|
||||
}
|
||||
catch {
|
||||
return {
|
||||
schemaVersion: ASSET_CATALOG_COMPATIBILITY_SCHEMA,
|
||||
task: "M12-01E",
|
||||
readerSchemaVersion: 1,
|
||||
documentSchemaVersion: 1,
|
||||
operation: requestedOperation,
|
||||
status: "BLOCKED",
|
||||
code: "ASSET_MANIFEST_INVALID",
|
||||
recoverable: true,
|
||||
sourceSha256,
|
||||
snapshot: null,
|
||||
nextTask: "M12-01F",
|
||||
};
|
||||
}
|
||||
return {
|
||||
schemaVersion: ASSET_CATALOG_COMPATIBILITY_SCHEMA,
|
||||
task: "M12-01E",
|
||||
readerSchemaVersion: 1,
|
||||
documentSchemaVersion: 1,
|
||||
operation: requestedOperation,
|
||||
status: "READY",
|
||||
code: null,
|
||||
recoverable: true,
|
||||
sourceSha256,
|
||||
snapshot: null,
|
||||
nextTask: "M12-01F",
|
||||
};
|
||||
}
|
||||
if (value.schemaVersion !== ASSET_CATALOG_SCHEMA) {
|
||||
return {
|
||||
schemaVersion: ASSET_CATALOG_COMPATIBILITY_SCHEMA,
|
||||
task: "M12-01E",
|
||||
readerSchemaVersion: 1,
|
||||
documentSchemaVersion: value.schemaVersion,
|
||||
operation: requestedOperation,
|
||||
status: "BLOCKED",
|
||||
code: "PROTOCOL_MISMATCH",
|
||||
recoverable: false,
|
||||
sourceSha256,
|
||||
snapshot: null,
|
||||
nextTask: "M12-01F",
|
||||
};
|
||||
}
|
||||
|
||||
let document;
|
||||
try {
|
||||
document = await parseAssetCatalogManifestV2(value);
|
||||
}
|
||||
catch {
|
||||
return {
|
||||
schemaVersion: ASSET_CATALOG_COMPATIBILITY_SCHEMA,
|
||||
task: "M12-01E",
|
||||
readerSchemaVersion: 1,
|
||||
documentSchemaVersion: ASSET_CATALOG_SCHEMA,
|
||||
operation: requestedOperation,
|
||||
status: "BLOCKED",
|
||||
code: "ASSET_MANIFEST_INVALID",
|
||||
recoverable: true,
|
||||
sourceSha256,
|
||||
snapshot: null,
|
||||
nextTask: "M12-01F",
|
||||
};
|
||||
}
|
||||
const snapshot: AssetCatalogLegacySnapshotIR = {
|
||||
revision: document.revision,
|
||||
catalogs: document.catalogs.map(({ catalogId, path, simpleName }) => ({ catalogId, path, simpleName })),
|
||||
assets: document.assets.map(({ assetId, relativeAssetIdentifier, idType, name, catalogId }) => ({ assetId, relativeAssetIdentifier, idType, name, catalogId })),
|
||||
libraries: document.libraries.map(({ libraryId, name, readOnly }) => ({ libraryId, name, readOnly })),
|
||||
};
|
||||
return {
|
||||
schemaVersion: ASSET_CATALOG_COMPATIBILITY_SCHEMA,
|
||||
task: "M12-01E",
|
||||
readerSchemaVersion: 1,
|
||||
documentSchemaVersion: ASSET_CATALOG_SCHEMA,
|
||||
operation: requestedOperation,
|
||||
status: requestedOperation === "READ" ? "READ_ONLY" : "BLOCKED",
|
||||
code: "ASSET_SCHEMA_DOWNGRADE_BLOCKED",
|
||||
recoverable: true,
|
||||
sourceSha256,
|
||||
snapshot,
|
||||
nextTask: "M12-01F",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user