release: v0.5.1 — 存储后端生产级硬化(CRC-32/全库加密/WAL分片/页面化存储/多标签页锁/e2e)+ 深度审查修复(假实现接线/死代码清理)
CI / test (18.x) (push) Successful in 10m10s
CI / test (20.x) (push) Successful in 10m10s
CI / test (22.x) (push) Successful in 10m6s
CI / e2e (push) Successful in 9m51s
CI / test (24.x) (push) Successful in 10m28s

This commit is contained in:
thzxx
2026-08-10 12:07:00 +08:00
parent cff98b0903
commit 334067d89e
88 changed files with 15713 additions and 10626 deletions
+88
View File
@@ -0,0 +1,88 @@
/**
* 测试共享 — 真实语义 OPFS mock
*
* 模拟 OPFS 的完整语义:
* - createWritable({ keepExistingData }) + position 追加写
* - 文件内容以 ArrayBuffer 存储(跨 backend 实例共享于同一 Map
* - entries() 迭代、removeEntry 删除
*
* 用法:
* const files = installOPFSMock(new Map());
* const backend = new OPFSBackend();
* await backend.open('any');
*/
export interface MockOpfsFile {
content: ArrayBuffer;
}
export function installOPFSMock(files: Map<string, MockOpfsFile>): {
files: Map<string, MockOpfsFile>;
dir: {
getFileHandle: (name: string, opts?: { create?: boolean }) => Promise<{
getFile: () => Promise<{ size: number; arrayBuffer: () => Promise<ArrayBuffer> }>;
createWritable: (wOpts?: { keepExistingData?: boolean }) => Promise<{
write: (arg: ArrayBuffer | { type: string; position: number; data: ArrayBuffer }) => Promise<void>;
close: () => Promise<void>;
}>;
}>;
entries: () => AsyncGenerator<[string]>;
removeEntry: (name: string) => Promise<void>;
};
} {
const getFileHandle = async (name: string, opts?: { create?: boolean }) => {
if (!files.has(name)) {
if (!opts?.create) throw new Error(`NotFoundError: ${name}`);
files.set(name, { content: new ArrayBuffer(0) });
}
const entry = files.get(name)!;
return {
getFile: async () => ({ size: entry.content.byteLength, arrayBuffer: async () => entry.content }),
createWritable: async (wOpts?: { keepExistingData?: boolean }) => {
const w: {
write: (arg: ArrayBuffer | { type: string; position: number; data: ArrayBuffer }) => Promise<void>;
close: () => Promise<void>;
} = {
write: async (arg) => {
const keepExisting = wOpts?.keepExistingData ?? false;
const chunk = (arg as { type?: string }).type === 'write'
? { data: (arg as { data: ArrayBuffer }).data, position: (arg as { position: number }).position }
: { data: arg as ArrayBuffer, position: keepExisting ? entry.content.byteLength : 0 };
const merged = new Uint8Array(chunk.position + chunk.data.byteLength);
if (keepExisting || chunk.position > 0) {
merged.set(new Uint8Array(entry.content), 0);
}
merged.set(new Uint8Array(chunk.data), chunk.position);
entry.content = merged.buffer;
},
close: async () => { /* no-op */ },
};
return w;
},
};
};
const dir = {
getFileHandle,
entries: async function* () {
for (const [name] of files) yield [name];
},
removeEntry: async (name: string) => {
files.delete(name);
},
};
Object.defineProperty(globalThis, 'navigator', {
value: {
storage: {
getDirectory: async () => ({
getDirectoryHandle: async (_name: string, _opts?: unknown) => dir,
}),
},
},
configurable: true,
writable: true,
});
return { files, dir };
}