import assert from 'node:assert/strict' import { createHash } from 'node:crypto' import test from 'node:test' import { CancelledError, ModelDownloadError, ModelIntegrityError, TripoSplatWebGPU, } from '../dist/index.js' import { clearModelCache, createRuntime, getModelCacheStatus, MemoryModelArtifactStorage, ModelArtifactManager, Sha256, sha256Hex, withVerifiedModelArtifacts, } from '../dist/low-level.js' import { prepareReusableGraphInputs } from '../dist/runtime.js' function bytes(value) { return new TextEncoder().encode(value) } function digest(value) { return createHash('sha256').update(value).digest('hex') } function graphDescriptor(graphBytes, shardBytes, suffix = '') { return { url: `https://cdn.example.test/model.onnx?signature=${suffix}`, byteLength: graphBytes.byteLength, integrity: { algorithm: 'sha256', digest: digest(graphBytes) }, externalData: [{ path: 'model.onnx.data', url: `https://cdn.example.test/model.onnx.data?signature=${suffix}`, byteLength: shardBytes.byteLength, integrity: { algorithm: 'sha256', digest: digest(shardBytes) }, }], } } test('incremental SHA-256 matches the standard digest', () => { assert.equal( sha256Hex(bytes('abc')), 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', ) for (const length of [0, 55, 56, 63, 64, 65, 1000]) { const value = new Uint8Array(length) for (let index = 0; index < length; index += 1) value[index] = index % 251 const hash = new Sha256() for (let offset = 0; offset < value.length; offset += 17) { hash.update(value.subarray(offset, Math.min(value.length, offset + 17))) } assert.equal(hash.hex(), digest(value), `SHA-256 mismatch at ${length} bytes`) } }) test('graph and external-data bytes are verified, cached, and reused without CDN access', async () => { const graphBytes = bytes('small onnx graph') const shardBytes = bytes('external tensor bytes') const graph = graphDescriptor(graphBytes, shardBytes, 'first') const storage = new MemoryModelArtifactStorage() const requests = [] const progress = [] const manager = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/revision/fp16', storage, requestInit: { headers: { authorization: 'Bearer local-test' } }, fetch: async (url, init) => { requests.push(String(url)) assert.equal(new Headers(init?.headers).get('authorization'), 'Bearer local-test') return new Response(String(url).includes('.data') ? shardBytes : graphBytes) }, onProgress: (event) => progress.push(event), }) const prepared = await manager.prepareGraph('dit', graph) try { assert.equal(prepared.graph.externalData[0].path, 'model.onnx.data') assert.deepEqual(new Uint8Array(await (await fetch(prepared.graph.url)).arrayBuffer()), graphBytes) assert.deepEqual( new Uint8Array(await (await fetch(prepared.graph.externalData[0].url)).arrayBuffer()), shardBytes, ) } finally { prepared.release() } assert.equal(requests.length, 2) assert.ok(progress.every(({ source }) => source === 'network')) const cacheProgress = [] const cachedManager = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/revision/fp16', storage, fetch: async () => { throw new Error('CDN should not be called for a verified cache hit.') }, onProgress: (event) => cacheProgress.push(event), }) const cached = await cachedManager.prepareGraph('dit', graphDescriptor(graphBytes, shardBytes, 'refreshed')) cached.release() assert.equal(cacheProgress.length, 2) assert.ok(cacheProgress.every(({ source }) => source === 'cache')) assert.equal((await cachedManager.status()).length, 2) }) test('persistent prefetch memoizes verified blobs for prepareGraph within one manager lifecycle', async () => { const artifact = bytes('prefetched persistent graph') const graph = { url: 'https://cdn.example.test/prefetched.onnx?signature=initial', byteLength: artifact.byteLength, integrity: { algorithm: 'sha256', digest: digest(artifact) }, } const storage = new MemoryModelArtifactStorage() const seed = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/prefetch/fp32', storage, fetch: async () => new Response(artifact), }) ;(await seed.prepareGraph('dino', graph)).release() const [entry] = await storage.entries() const record = await storage.get(entry.cacheKey) let hashReads = 0 record.blob = new class extends Blob { stream() { hashReads += 1 return super.stream() } }([record.blob]) const originalGet = storage.get.bind(storage) let storageReads = 0 storage.get = async (cacheKey) => { storageReads += 1 return originalGet(cacheKey) } const manager = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/prefetch/fp32', storage, fetch: async () => { throw new Error('verified persistent bytes should not be downloaded again') }, }) await manager.prefetchManifest({ name: 'triposplat-webgpu', version: '1', modelRevision: 'prefetch', precision: 'fp32', graphs: { dino: graph }, }) const prepared = await manager.prepareGraph('dino', { ...graph, url: 'https://cdn.example.test/prefetched.onnx?signature=refreshed', }) prepared.release() assert.equal(storageReads, 1) assert.equal(hashReads, 1) }) test("cache 'none' never retains verified artifacts between prepareGraph calls", async () => { const artifact = bytes('non-persistent graph') const storage = new MemoryModelArtifactStorage() let downloads = 0 const manager = new ModelArtifactManager({ backend: 'none', namespace: 'triposplat/1/no-retention/fp32', storage, fetch: async () => { downloads += 1 return new Response(artifact) }, }) const graph = { url: 'https://cdn.example.test/non-persistent.onnx', byteLength: artifact.byteLength, integrity: { algorithm: 'sha256', digest: digest(artifact) }, } for (let run = 0; run < 2; run += 1) { const prepared = await manager.prepareGraph('dino', graph) prepared.release() await new Promise((resolve) => setTimeout(resolve, 0)) assert.deepEqual(await storage.entries(), []) } assert.equal(downloads, 2) }) test('artifact fetch implementations are invoked without a ModelArtifactManager receiver', async () => { const artifact = bytes('unbound fetch graph') let receiver const manager = new ModelArtifactManager({ backend: 'none', namespace: 'triposplat/1/unbound-fetch/fp32', fetch: async function () { receiver = this return new Response(artifact) }, }) const prepared = await manager.prepareGraph('dino', { url: 'https://cdn.example.test/unbound-fetch.onnx', byteLength: artifact.byteLength, integrity: { algorithm: 'sha256', digest: digest(artifact) }, }) prepared.release() assert.equal(receiver, undefined) }) test('integrity or byte-length mismatch is rejected before an artifact is committed', async () => { const storage = new MemoryModelArtifactStorage() const manager = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/bad/fp16', storage, fetch: async () => new Response(bytes('corrupted')), }) const graph = { url: 'https://cdn.example.test/bad.onnx', byteLength: 999, integrity: { algorithm: 'sha256', digest: '0'.repeat(64) }, } await assert.rejects( manager.prepareGraph('dino', graph), (error) => error instanceof ModelIntegrityError && error.code === 'MODEL_INTEGRITY_FAILED' && error.diagnostics.expectedByteLength === 999, ) assert.deepEqual(await storage.entries(), []) }) test('verified runtime wrapper gives ORT local Blob URLs and revokes them after session creation', async () => { const graphBytes = bytes('worker graph bytes') const shardBytes = bytes('worker shard bytes') const graph = graphDescriptor(graphBytes, shardBytes, 'runtime') let capturedGraphUrl let capturedShardUrl const controller = new AbortController() const delegate = { disposed: false, async loadGraph(sessionId, prepared, options) { capturedGraphUrl = prepared.url capturedShardUrl = prepared.externalData[0].url assert.deepEqual(new Uint8Array(await (await fetch(prepared.url)).arrayBuffer()), graphBytes) assert.deepEqual( new Uint8Array(await (await fetch(prepared.externalData[0].url)).arrayBuffer()), shardBytes, ) assert.equal(options.signal, controller.signal) return { sessionId, executionProvider: 'webgpu', inputNames: [], outputNames: [], loadMs: 1, } }, async runGraph() { throw new Error('not used') }, async disposeGraph() { return true }, async dispose() { this.disposed = true }, } const manager = new ModelArtifactManager({ backend: 'none', namespace: 'triposplat/1/runtime/fp16', fetch: async (url) => new Response(String(url).includes('.data') ? shardBytes : graphBytes), }) const runtime = withVerifiedModelArtifacts(delegate, manager, { 'triposplat/dit': 'dit' }) await runtime.loadGraph('triposplat/dit', graph, { signal: controller.signal }) await assert.rejects(fetch(capturedGraphUrl)) await assert.rejects(fetch(capturedShardUrl)) await runtime.dispose() assert.equal(delegate.disposed, true) }) test('verified runtime wrapper preserves built-in reusable-input worker capability', async () => { const messages = [] const worker = { onmessage: null, onerror: null, onmessageerror: null, postMessage(request, transfer = []) { const delivered = structuredClone(request, { transfer }) messages.push(delivered) queueMicrotask(() => { const result = delivered.type === 'configure' ? { operation: 'configure', configured: true } : delivered.type === 'retain-inputs' ? { operation: 'retain-inputs', retainedInputNames: Object.keys(delivered.inputs) } : { operation: 'dispose', disposedSessionIds: [] } this.onmessage?.({ data: { type: 'reply', requestId: delivered.requestId, ok: true, result }, }) }) }, terminate() {}, } const base = createRuntime({ workerFactory: () => worker }) const manager = new ModelArtifactManager({ backend: 'none', namespace: 'triposplat/1/reusable-wrapper/fp32', }) const runtime = withVerifiedModelArtifacts(base, manager, {}) const feature = Float32Array.of(1, 2, 3, 4) await prepareReusableGraphInputs( runtime, 'triposplat/dit', 'condition', { feature: { type: 'float32', data: feature, dims: [1, 4] } }, ) assert.equal(feature.byteLength, 0) assert.equal(messages.filter(({ type }) => type === 'retain-inputs').length, 1) await runtime.dispose() }) test('corrupt cached bytes are evicted and replaced from the authoritative object', async () => { const original = bytes('verified bytes') const storage = new MemoryModelArtifactStorage() const graph = { url: 'https://cdn.example.test/verified.onnx', byteLength: original.byteLength, integrity: { algorithm: 'sha256', digest: digest(original) }, } const first = new ModelArtifactManager({ backend: 'opfs', namespace: 'triposplat/1/revision/fp16', storage, fetch: async () => new Response(original), }) ;(await first.prepareGraph('vae', graph)).release() const [entry] = await storage.entries() const record = await storage.get(entry.cacheKey) record.blob = new Blob([bytes('tampered local bytes')]) let downloads = 0 const second = new ModelArtifactManager({ backend: 'opfs', namespace: 'triposplat/1/revision/fp16', storage, fetch: async () => { downloads += 1 return new Response(original) }, }) ;(await second.prepareGraph('vae', graph)).release() assert.equal(downloads, 1) assert.equal((await storage.entries()).length, 1) }) test('cache namespaces isolate revisions and targeted clear preserves other revisions', async () => { const data = bytes('same immutable artifact') const storage = new MemoryModelArtifactStorage() const graph = { url: 'https://cdn.example.test/model.onnx', byteLength: data.byteLength, integrity: { algorithm: 'sha256', digest: digest(data) }, } for (const namespace of ['triposplat/1/rev-a/fp16', 'triposplat/2/rev-b/fp16']) { const manager = new ModelArtifactManager({ backend: 'cache-api', namespace, storage, fetch: async () => new Response(data), }) ;(await manager.prepareGraph('octree', graph)).release() } assert.equal((await storage.entries()).length, 2) await storage.clear('triposplat/1/rev-a/fp16') const remaining = await storage.entries() assert.equal(remaining.length, 1) assert.equal(remaining[0].namespace, 'triposplat/2/rev-b/fp16') }) test('aborted artifact streams leave no cache entry', async () => { const storage = new MemoryModelArtifactStorage() const controller = new AbortController() const manager = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/cancelled/fp16', storage, fetch: async () => new Response(new ReadableStream({ start(stream) { stream.enqueue(bytes('first chunk')) stream.enqueue(bytes('second chunk')) stream.close() }, })), onProgress() { controller.abort('test cancellation') }, }) await assert.rejects( manager.prepareGraph('gaussianDecoder', { url: 'https://cdn.example.test/large.onnx' }, controller.signal), (error) => error instanceof CancelledError, ) assert.deepEqual(await storage.entries(), []) }) test('Cache API status and clear report verified persistent entries', async () => { const originalCaches = globalThis.caches const stores = new Map() const cache = { async match(request) { return stores.get(request.url)?.clone() }, async put(request, response) { const body = await response.blob() stores.set(request.url, new Response(body, { headers: response.headers })) }, async delete(request) { return stores.delete(request.url) }, async keys() { return Array.from(stores.keys(), (url) => new Request(url)) }, } globalThis.caches = { async open() { return cache }, async delete() { stores.clear(); return true }, } try { const data = bytes('cache api bytes') const manager = new ModelArtifactManager({ backend: 'cache-api', namespace: 'triposplat/1/cache-api/fp16', fetch: async () => new Response(data), }) ;(await manager.prepareGraph('dino', { url: 'https://cdn.example.test/cache-api.onnx', byteLength: data.byteLength, integrity: { algorithm: 'sha256', digest: digest(data) }, })).release() const status = await getModelCacheStatus({ backend: 'cache-api' }) assert.equal(status.entryCount, 1) assert.equal(status.totalBytes, data.byteLength) assert.equal(status.backends[0].available, true) await clearModelCache({ backend: 'cache-api' }) assert.equal((await getModelCacheStatus({ backend: 'cache-api' })).entryCount, 0) } finally { if (originalCaches === undefined) delete globalThis.caches else globalThis.caches = originalCaches } }) test('high-level load prefetches persistent artifacts and reuses them across model instances', async () => { const originalCaches = globalThis.caches const stores = new Map() const cache = { async match(request) { return stores.get(request.url)?.clone() }, async put(request, response) { const body = await response.blob() stores.set(request.url, new Response(body, { headers: response.headers })) }, async delete(request) { return stores.delete(request.url) }, async keys() { return Array.from(stores.keys(), (url) => new Request(url)) }, } globalThis.caches = { async open() { return cache }, async delete() { stores.clear(); return true }, } const artifact = bytes('high-level graph') const workerFactory = () => ({ onmessage: null, onerror: null, onmessageerror: null, postMessage(request) { queueMicrotask(() => { const result = request.type === 'configure' ? { operation: 'configure', configured: true } : { operation: 'dispose', disposedSessionIds: [] } this.onmessage?.({ data: { type: 'reply', requestId: request.requestId, ok: true, result } }) }) }, terminate() {}, }) let artifactDownloads = 0 let manifestRevision = 0 const customFetch = async (url, init) => { if (String(url).endsWith('manifest.json')) { manifestRevision += 1 assert.equal(new Headers(init?.headers).get('x-manifest'), 'manifest-header') return Response.json({ name: 'triposplat-webgpu', version: '1.0.0', modelRevision: 'immutable-revision', precision: 'fp16', graphs: { dino: { url: `dino.onnx?signature=${manifestRevision}`, byteLength: artifact.byteLength, integrity: { algorithm: 'sha256', digest: digest(artifact) }, }, }, }) } artifactDownloads += 1 assert.equal(new Headers(init?.headers).get('authorization'), 'Bearer artifact-header') return new Response(artifact) } try { for (let run = 0; run < 2; run += 1) { const progress = [] const model = new TripoSplatWebGPU({ modelBaseUrl: 'https://cdn.example.test/model/', executionProviders: ['wasm'], cache: 'cache-api', fetch: customFetch, manifestRequestInit: { headers: { 'x-manifest': 'manifest-header' } }, artifactRequestInit: { headers: { authorization: 'Bearer artifact-header' } }, workerFactory, }) await model.load({ onProgress: (event) => progress.push(event) }) assert.ok(progress.some((event) => event.stage === 'graphs')) await model.dispose() } assert.equal(artifactDownloads, 1) } finally { if (originalCaches === undefined) delete globalThis.caches else globalThis.caches = originalCaches } }) test("cache 'none' streams through temporary OPFS and deletes the staged file on release", async () => { const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator') const files = new Map() const directory = { async getFileHandle(name, options = {}) { if (!files.has(name)) { if (!options.create) throw new DOMException('Not found', 'NotFoundError') files.set(name, { parts: [] }) } const record = files.get(name) return { async createWritable() { record.parts = [] return { async write(value) { const bytes = value instanceof ArrayBuffer ? new Uint8Array(value) : new Uint8Array(value.buffer, value.byteOffset, value.byteLength) record.parts.push(bytes.slice().buffer) }, async close() {}, async abort() { record.parts = [] }, } }, async getFile() { return new Blob(record.parts) }, } }, async removeEntry(name) { files.delete(name) }, async *entries() { for (const name of files.keys()) yield [name, {}] }, } const root = { async getDirectoryHandle() { return directory } } Object.defineProperty(globalThis, 'navigator', { configurable: true, value: { storage: { async getDirectory() { return root } } }, }) try { const artifact = bytes('disk-backed ephemeral graph') const manager = new ModelArtifactManager({ backend: 'none', namespace: 'triposplat/1/ephemeral/fp32', fetch: async () => new Response(artifact), }) const prepared = await manager.prepareGraph('dino', { url: 'https://cdn.example.test/ephemeral.onnx', byteLength: artifact.byteLength, integrity: { algorithm: 'sha256', digest: digest(artifact) }, }) assert.equal(files.size, 1) assert.deepEqual( new Uint8Array(await (await fetch(prepared.graph.url)).arrayBuffer()), artifact, ) prepared.release() await new Promise((resolve) => setTimeout(resolve, 0)) assert.equal(files.size, 0) manager.dispose() } finally { if (originalNavigator) Object.defineProperty(globalThis, 'navigator', originalNavigator) else delete globalThis.navigator } }) test('default OPFS load fails before downloading when declared artifacts exceed origin quota', async () => { const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator') const directory = { async *entries() {}, async removeEntry() {}, } const root = { async getDirectoryHandle() { return directory } } let persisted = false Object.defineProperty(globalThis, 'navigator', { configurable: true, value: { storage: { async getDirectory() { return root }, async persist() { persisted = true; return true }, async estimate() { return { quota: 100, usage: 10 } }, }, }, }) let workerCreated = false const model = new TripoSplatWebGPU({ modelBaseUrl: 'https://cdn.example.test/quota/', executionProviders: ['wasm'], fetch: async (url) => { assert.match(String(url), /manifest\.json$/) return Response.json({ name: 'triposplat-webgpu', version: 'quota-test', modelRevision: 'quota-test', precision: 'fp32', estimatedModelBytes: 1000, graphs: {}, }) }, workerFactory: () => { workerCreated = true throw new Error('quota preflight must run before worker creation') }, }) try { await assert.rejects( model.load(), (error) => error instanceof ModelDownloadError && error.diagnostics.requiredBytes === 1000 && error.diagnostics.availableBytes === 90, ) assert.equal(persisted, true) assert.equal(workerCreated, false) } finally { await model.dispose() if (originalNavigator) Object.defineProperty(globalThis, 'navigator', originalNavigator) else delete globalThis.navigator } })