Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer, web workflow engine and protocol, tooling, docs and task records. Large generated evidence, user-testing archives, build snapshots and imported test assets remain untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
23 lines
1.6 KiB
TypeScript
23 lines
1.6 KiB
TypeScript
import { normalizeProjectAssetPath } from './asset-path';
|
|
|
|
export const EDITOR_RESOURCE_MAX_BYTES = 256 * 1024 * 1024;
|
|
export const SHADER_BUNDLE_MAX_FILES = 256;
|
|
export interface ShaderResourceSelection { batchId: string; relativePath: string }
|
|
export function isEditorResourcePath(value: unknown): value is string {
|
|
if (typeof value !== 'string') return false;
|
|
const parts = value.split('/'), bytes = new TextEncoder();
|
|
if (parts[0] !== 'cache' || !/^[0-9a-f-]{36}$/.test(parts[1] ?? '') || parts.length < 3 || parts.length > 16 || bytes.encode('/browser/' + value).length > 1023) return false;
|
|
if (parts.some(part => !part || part === '.' || part === '..' || /[\\\u0000-\u001f\u007f]/.test(part) || bytes.encode(part).length > 200)) return false;
|
|
try { if (normalizeProjectAssetPath(value) !== value) return false; } catch { return false; }
|
|
return parts[2] === 'shader' || parts[2] === 'model' ? parts.length > 3 : parts.length === 3 && /^[A-Za-z0-9._-]{1,200}\.(?:abc|usd|usda|usdc|usdz|btx|osl|oso)$/i.test(parts[2]);
|
|
}
|
|
export function modelResourcePath(batchId: string, relativePath: string): string {
|
|
const path = `cache/${batchId}/model/${relativePath}`;
|
|
if (!isEditorResourcePath(path)) throw new Error('请选择不含路径跳转的模型相对路径');
|
|
return path;
|
|
}
|
|
export function shaderResourcePath(selection: ShaderResourceSelection): string {
|
|
const path = `cache/${selection.batchId}/shader/${selection.relativePath}`;
|
|
if (!isEditorResourcePath(path)) throw new Error('Choose a bounded shader-relative path without traversal or renamed characters'); return path;
|
|
}
|