/** * 完整导入源的增量 SHA256:有界 Blob 分块读取,不把全文件放进 UI ArrayBuffer。 * 摘要是源完整性/稳定身份依据,不证明该文件有权限、schema 正确或所有记录已加入画布。 */ import { fault } from '../canvas-core/values.ts'; import {createSha256} from './sha256.ts'; /** Complete-source SHA-256, with bounded chunk memory and cooperative fallback scheduling. */ /** 顺序 slice 读取完整 Blob,默认 64KiB 分块(配置上限 4MiB),空文件也返回合法摘要。 * 每块读前/读后及 yield 后检查取消;原生 arrayBuffer/yield 本身不被信号强制终止。 * 默认块间 setTimeout(0) 让出,只有仍有下一块才 yield;自定义 yieldTask 决定实际调度公平性。 * 块内 hash.update 为同步 CPU 工作,不会中途取消;读/让出错误直接传播,不返回部分摘要。 */ export async function importSourceDigest(bytes:Blob,signal?:AbortSignal,options:{chunkBytes?:number;yieldTask?:()=>Promise}={}):Promise{ const chunk=options.chunkBytes??64*1024,yieldTask=options.yieldTask??(()=>new Promise(resolve=>setTimeout(resolve,0))); if(!(bytes instanceof Blob)||!Number.isSafeInteger(chunk)||chunk<1||chunk>4*1024*1024)throw fault('invalid_digest_input'); /** 读/计算/让出边界统一检查 signal;异步读取即使无法中止,迟到字节也不再参与有效结果。 */ const check=()=>{if(signal?.aborted)throw fault('import_aborted');};check();const hash=createSha256(); // 只顺序持有当前块,hash 自身不累计输入;part 在本次迭代/yield 期间仍可存在,实际释放时机由 GC 决定。 // 空文件跳过读取/让出,最后 check 后直接 hex;有界分块不是整个应用进程的内存硬上限。 for(let cursor=0;cursor