@powerhousedao/pglite-fs 6.2.2-dev.8 → 6.2.2-dev.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -224,8 +224,8 @@ function restoreMemfs(FS, root, bytes) {
224
224
  const dataLen = view.getUint32(off, true);
225
225
  off += 4;
226
226
  const full = root + "/" + relPath;
227
- if (type === 0) if (!FS.analyzePath(full).exists) FS.mkdir(full, mode);
228
- else FS.chmod(full, mode);
227
+ if (type === 0) if (!FS.analyzePath(full).exists) FS.mkdir(full, dirMode(mode));
228
+ else FS.chmod(full, dirMode(mode));
229
229
  else {
230
230
  const data = bytes.subarray(off, off + dataLen);
231
231
  FS.writeFile(full, data);
@@ -234,6 +234,19 @@ function restoreMemfs(FS, root, bytes) {
234
234
  off += dataLen;
235
235
  }
236
236
  }
237
+ /**
238
+ * Permission bits for a directory created in MEMFS.
239
+ *
240
+ * Windows has no execute bit, so `fs.stat` reports every directory as 0o40666.
241
+ * Copying that mode verbatim produces a MEMFS directory that cannot be
242
+ * traversed, and every lookup beneath it fails with ENOENT -- which surfaces
243
+ * as PGLite throwing a bare `ErrnoError { errno: 2 }` on the first query after
244
+ * a legacy migration. Force the traverse bit on. MEMFS is process-local and
245
+ * rebuilt from disk on every open, so host permissions carry no meaning here.
246
+ */
247
+ function dirMode(mode) {
248
+ return mode & 4095 | 73;
249
+ }
237
250
  async function loadLegacyIntoMemfs(FS, root, hostDir) {
238
251
  ensureDir(FS, root);
239
252
  const skip = new Set([
@@ -249,7 +262,7 @@ async function loadLegacyIntoMemfs(FS, root, hostDir) {
249
262
  const memFull = memPath + "/" + ent.name;
250
263
  const stat = await promises.stat(diskFull);
251
264
  if (ent.isDirectory()) {
252
- if (!FS.analyzePath(memFull).exists) FS.mkdir(memFull, stat.mode & 4095);
265
+ if (!FS.analyzePath(memFull).exists) FS.mkdir(memFull, dirMode(stat.mode));
253
266
  await walk(diskFull, memFull);
254
267
  } else if (ent.isFile()) {
255
268
  const data = await promises.readFile(diskFull);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["fs"],"sources":["../src/atomic-node-fs.ts"],"sourcesContent":["import { MemoryFS } from \"@electric-sql/pglite\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\n// PGDATA in PGLite 0.3.x's MEMFS layout. The compiled bundle uses\n// `/tmp/pglite/base` (PG install prefix `/tmp/pglite`, data dir `base/` inside\n// it). Not exported as a runtime constant, so we hardcode.\nconst PGDATA = \"/tmp/pglite/base\";\nconst SNAPSHOT_NAME = \"snapshot.bin\";\nconst SNAPSHOT_TMP = \"snapshot.bin.tmp\";\nconst MAGIC = new Uint8Array([0x50, 0x47, 0x4c, 0x41]); // \"PGLA\"\nconst FORMAT_VERSION = 1;\n\ntype EntryType = 0 | 1; // 0=dir, 1=file\n\ninterface MemFs {\n readdir(path: string): string[];\n stat(path: string): { mode: number; size: number };\n readFile(path: string, opts?: { encoding: \"binary\" }): Uint8Array;\n writeFile(path: string, data: Uint8Array): void;\n mkdir(path: string, mode?: number): void;\n chmod(path: string, mode: number): void;\n analyzePath(path: string): { exists: boolean };\n isDir(mode: number): boolean;\n isFile(mode: number): boolean;\n}\n\nexport interface AtomicNodeFsLogger {\n warn(message: string): void;\n}\n\nexport interface AtomicNodeFsOptions {\n logger?: AtomicNodeFsLogger;\n /**\n * Coalesce `syncToFs` calls into a trailing-edge disk write at most every\n * `flushIntervalMs` milliseconds. PGLite calls `syncToFs` after every\n * non-transactional query (including each BEGIN/INSERT/COMMIT emitted by\n * Kysely), so a synchronous full-tree snapshot per call caps write\n * throughput at one query per snapshot duration. Deferred mode trades\n * worst-case crash loss of up to `flushIntervalMs` of writes for sustained\n * throughput. `closeFs` always drains pending writes durably before\n * returning.\n *\n * Default `0` preserves the original per-call synchronous behavior.\n */\n flushIntervalMs?: number;\n}\n\n/**\n * PGLite Filesystem that holds the working data dir in Emscripten MEMFS and\n * atomically swaps a single-file on-disk snapshot on `syncToFs`. A SIGKILL\n * mid-write leaves the previous snapshot intact, so the next startup loads\n * cleanly rather than aborting on torn WAL.\n *\n * Intended for local dev use — full-tree snapshots are fine at dev volume but\n * won't scale to production write rates. For write-heavy workloads, pass\n * `flushIntervalMs` to coalesce multiple PGLite syncs into one disk write.\n */\nexport class AtomicNodeFs extends MemoryFS {\n private readonly hostDir: string;\n private readonly logger?: AtomicNodeFsLogger;\n private readonly flushIntervalMs: number;\n\n private dirty = false;\n private flushTimer?: ReturnType<typeof setTimeout>;\n private flushInFlight?: Promise<void>;\n\n constructor(\n hostDir: string,\n optionsOrLogger?: AtomicNodeFsOptions | AtomicNodeFsLogger,\n ) {\n super();\n this.hostDir = path.resolve(hostDir);\n const options = normalizeOptions(optionsOrLogger);\n this.logger = options.logger;\n this.flushIntervalMs = Math.max(0, options.flushIntervalMs ?? 0);\n }\n\n async initialSyncFs(): Promise<void> {\n await fs.mkdir(this.hostDir, { recursive: true });\n const snapPath = path.join(this.hostDir, SNAPSHOT_NAME);\n const tmpPath = path.join(this.hostDir, SNAPSHOT_TMP);\n\n // Drop any leftover staging file from a prior crashed write.\n await fs.rm(tmpPath, { force: true });\n\n const memFs = this.pg!.Module.FS as MemFs;\n\n if (await fileExists(snapPath)) {\n const bytes = await fs.readFile(snapPath);\n restoreMemfs(memFs, PGDATA, bytes);\n return;\n }\n\n const legacyMarker = path.join(this.hostDir, \"PG_VERSION\");\n if (await fileExists(legacyMarker)) {\n this.logger?.warn(\n `Migrating legacy PGLite data dir at ${this.hostDir} to atomic snapshot. Original files retained alongside snapshot.bin as a backup; remove them once the new snapshot is verified.`,\n );\n await loadLegacyIntoMemfs(memFs, PGDATA, this.hostDir);\n return;\n }\n }\n\n async syncToFs(relaxedDurability?: boolean): Promise<void> {\n if (this.flushIntervalMs === 0) {\n await this.writeSnapshot(relaxedDurability ?? false);\n return;\n }\n this.dirty = true;\n this.scheduleDeferredFlush(relaxedDurability ?? false);\n }\n\n async closeFs(): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n while (this.flushInFlight) {\n await this.flushInFlight;\n }\n this.dirty = false;\n await this.writeSnapshot(false);\n await super.closeFs();\n }\n\n private scheduleDeferredFlush(relaxedDurability: boolean): void {\n if (this.flushTimer || this.flushInFlight) return;\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined;\n this.flushInFlight = this.drainDirty(relaxedDurability)\n .catch((err) => {\n this.logger?.warn(\n `AtomicNodeFs deferred flush failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n })\n .finally(() => {\n this.flushInFlight = undefined;\n });\n }, this.flushIntervalMs);\n // Don't keep the event loop alive solely for a pending flush; closeFs is\n // responsible for draining before shutdown.\n this.flushTimer.unref?.();\n }\n\n private async drainDirty(relaxedDurability: boolean): Promise<void> {\n while (this.dirty) {\n this.dirty = false;\n await this.writeSnapshot(relaxedDurability);\n }\n }\n\n private async writeSnapshot(relaxedDurability: boolean): Promise<void> {\n const memFs = this.pg!.Module.FS as MemFs;\n const bytes = serializeMemfs(memFs, PGDATA);\n const snapPath = path.join(this.hostDir, SNAPSHOT_NAME);\n const tmpPath = path.join(this.hostDir, SNAPSHOT_TMP);\n\n const fh = await fs.open(tmpPath, \"w\");\n try {\n await fh.write(bytes);\n if (!relaxedDurability) await fh.sync();\n } finally {\n await fh.close();\n }\n\n await fs.rename(tmpPath, snapPath);\n\n if (!relaxedDurability) {\n try {\n const dirFh = await fs.open(this.hostDir, \"r\");\n try {\n await dirFh.sync();\n } finally {\n await dirFh.close();\n }\n } catch {\n // Some platforms reject fsync on a directory fd. The rename itself is\n // still atomic at the inode level; durability of the directory entry\n // is best-effort.\n }\n }\n }\n}\n\nfunction normalizeOptions(\n optionsOrLogger: AtomicNodeFsOptions | AtomicNodeFsLogger | undefined,\n): AtomicNodeFsOptions {\n if (!optionsOrLogger) return {};\n if (isLogger(optionsOrLogger)) {\n return { logger: optionsOrLogger };\n }\n return optionsOrLogger;\n}\n\nfunction isLogger(\n value: AtomicNodeFsOptions | AtomicNodeFsLogger,\n): value is AtomicNodeFsLogger {\n return (\n \"warn\" in value && typeof (value as AtomicNodeFsLogger).warn === \"function\"\n );\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensureDir(FS: MemFs, dir: string): void {\n const parts = dir.split(\"/\").filter(Boolean);\n let cur = \"\";\n for (const p of parts) {\n cur += \"/\" + p;\n if (!FS.analyzePath(cur).exists) FS.mkdir(cur);\n }\n}\n\ninterface Entry {\n type: EntryType;\n mode: number;\n relPath: string;\n data?: Uint8Array;\n}\n\nfunction serializeMemfs(FS: MemFs, root: string): Uint8Array {\n const entries: Entry[] = [];\n\n const walk = (dir: string, rel: string) => {\n const names = FS.readdir(dir);\n for (const name of names) {\n if (name === \".\" || name === \"..\") continue;\n const full = dir + \"/\" + name;\n const r = rel === \"\" ? name : rel + \"/\" + name;\n const stat = FS.stat(full);\n if (FS.isDir(stat.mode)) {\n entries.push({ type: 0, mode: stat.mode & 0o7777, relPath: r });\n walk(full, r);\n } else if (FS.isFile(stat.mode)) {\n const data = FS.readFile(full, { encoding: \"binary\" });\n entries.push({\n type: 1,\n mode: stat.mode & 0o7777,\n relPath: r,\n data,\n });\n }\n // skip symlinks, sockets, etc. — PGLite doesn't create them in PGDATA.\n }\n };\n walk(root, \"\");\n\n const encoder = new TextEncoder();\n const encodedPaths = entries.map((e) => encoder.encode(e.relPath));\n\n let size = 4 + 4 + 4; // magic + version + count\n for (let i = 0; i < entries.length; i++) {\n size += 1 + 4 + 4 + encodedPaths[i].byteLength + 4;\n size += entries[i].data?.byteLength ?? 0;\n }\n\n const out = new Uint8Array(size);\n const view = new DataView(out.buffer);\n let off = 0;\n\n out.set(MAGIC, off);\n off += 4;\n view.setUint32(off, FORMAT_VERSION, true);\n off += 4;\n view.setUint32(off, entries.length, true);\n off += 4;\n\n for (let i = 0; i < entries.length; i++) {\n const e = entries[i];\n const pathBytes = encodedPaths[i];\n view.setUint8(off, e.type);\n off += 1;\n view.setUint32(off, e.mode, true);\n off += 4;\n view.setUint32(off, pathBytes.byteLength, true);\n off += 4;\n out.set(pathBytes, off);\n off += pathBytes.byteLength;\n const dataLen = e.data?.byteLength ?? 0;\n view.setUint32(off, dataLen, true);\n off += 4;\n if (dataLen > 0 && e.data) {\n out.set(e.data, off);\n off += dataLen;\n }\n }\n\n return out;\n}\n\nfunction restoreMemfs(FS: MemFs, root: string, bytes: Uint8Array): void {\n ensureDir(FS, root);\n\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n let off = 0;\n\n for (let i = 0; i < 4; i++) {\n if (bytes[off + i] !== MAGIC[i]) {\n throw new Error(\"AtomicNodeFs: invalid snapshot magic\");\n }\n }\n off += 4;\n\n const version = view.getUint32(off, true);\n off += 4;\n if (version !== FORMAT_VERSION) {\n throw new Error(`AtomicNodeFs: unsupported snapshot version ${version}`);\n }\n const count = view.getUint32(off, true);\n off += 4;\n\n const decoder = new TextDecoder();\n\n for (let i = 0; i < count; i++) {\n const type = view.getUint8(off);\n off += 1;\n const mode = view.getUint32(off, true);\n off += 4;\n const pathLen = view.getUint32(off, true);\n off += 4;\n const relPath = decoder.decode(bytes.subarray(off, off + pathLen));\n off += pathLen;\n const dataLen = view.getUint32(off, true);\n off += 4;\n const full = root + \"/\" + relPath;\n\n if (type === 0) {\n if (!FS.analyzePath(full).exists) FS.mkdir(full, mode);\n else FS.chmod(full, mode);\n } else {\n const data = bytes.subarray(off, off + dataLen);\n FS.writeFile(full, data);\n FS.chmod(full, mode);\n }\n off += dataLen;\n }\n}\n\nasync function loadLegacyIntoMemfs(\n FS: MemFs,\n root: string,\n hostDir: string,\n): Promise<void> {\n ensureDir(FS, root);\n\n const skip = new Set([SNAPSHOT_NAME, SNAPSHOT_TMP, \"postmaster.pid\"]);\n\n const walk = async (diskPath: string, memPath: string) => {\n const ents = await fs.readdir(diskPath, { withFileTypes: true });\n for (const ent of ents) {\n if (skip.has(ent.name)) continue;\n const diskFull = path.join(diskPath, ent.name);\n const memFull = memPath + \"/\" + ent.name;\n const stat = await fs.stat(diskFull);\n if (ent.isDirectory()) {\n if (!FS.analyzePath(memFull).exists) {\n FS.mkdir(memFull, stat.mode & 0o7777);\n }\n await walk(diskFull, memFull);\n } else if (ent.isFile()) {\n const data = await fs.readFile(diskFull);\n FS.writeFile(memFull, data);\n FS.chmod(memFull, stat.mode & 0o7777);\n }\n }\n };\n\n await walk(hostDir, root);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["fs"],"sources":["../src/atomic-node-fs.ts"],"sourcesContent":["import { MemoryFS } from \"@electric-sql/pglite\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\n// PGDATA in PGLite 0.3.x's MEMFS layout. The compiled bundle uses\n// `/tmp/pglite/base` (PG install prefix `/tmp/pglite`, data dir `base/` inside\n// it). Not exported as a runtime constant, so we hardcode.\nconst PGDATA = \"/tmp/pglite/base\";\nconst SNAPSHOT_NAME = \"snapshot.bin\";\nconst SNAPSHOT_TMP = \"snapshot.bin.tmp\";\nconst MAGIC = new Uint8Array([0x50, 0x47, 0x4c, 0x41]); // \"PGLA\"\nconst FORMAT_VERSION = 1;\n\ntype EntryType = 0 | 1; // 0=dir, 1=file\n\ninterface MemFs {\n readdir(path: string): string[];\n stat(path: string): { mode: number; size: number };\n readFile(path: string, opts?: { encoding: \"binary\" }): Uint8Array;\n writeFile(path: string, data: Uint8Array): void;\n mkdir(path: string, mode?: number): void;\n chmod(path: string, mode: number): void;\n analyzePath(path: string): { exists: boolean };\n isDir(mode: number): boolean;\n isFile(mode: number): boolean;\n}\n\nexport interface AtomicNodeFsLogger {\n warn(message: string): void;\n}\n\nexport interface AtomicNodeFsOptions {\n logger?: AtomicNodeFsLogger;\n /**\n * Coalesce `syncToFs` calls into a trailing-edge disk write at most every\n * `flushIntervalMs` milliseconds. PGLite calls `syncToFs` after every\n * non-transactional query (including each BEGIN/INSERT/COMMIT emitted by\n * Kysely), so a synchronous full-tree snapshot per call caps write\n * throughput at one query per snapshot duration. Deferred mode trades\n * worst-case crash loss of up to `flushIntervalMs` of writes for sustained\n * throughput. `closeFs` always drains pending writes durably before\n * returning.\n *\n * Default `0` preserves the original per-call synchronous behavior.\n */\n flushIntervalMs?: number;\n}\n\n/**\n * PGLite Filesystem that holds the working data dir in Emscripten MEMFS and\n * atomically swaps a single-file on-disk snapshot on `syncToFs`. A SIGKILL\n * mid-write leaves the previous snapshot intact, so the next startup loads\n * cleanly rather than aborting on torn WAL.\n *\n * Intended for local dev use — full-tree snapshots are fine at dev volume but\n * won't scale to production write rates. For write-heavy workloads, pass\n * `flushIntervalMs` to coalesce multiple PGLite syncs into one disk write.\n */\nexport class AtomicNodeFs extends MemoryFS {\n private readonly hostDir: string;\n private readonly logger?: AtomicNodeFsLogger;\n private readonly flushIntervalMs: number;\n\n private dirty = false;\n private flushTimer?: ReturnType<typeof setTimeout>;\n private flushInFlight?: Promise<void>;\n\n constructor(\n hostDir: string,\n optionsOrLogger?: AtomicNodeFsOptions | AtomicNodeFsLogger,\n ) {\n super();\n this.hostDir = path.resolve(hostDir);\n const options = normalizeOptions(optionsOrLogger);\n this.logger = options.logger;\n this.flushIntervalMs = Math.max(0, options.flushIntervalMs ?? 0);\n }\n\n async initialSyncFs(): Promise<void> {\n await fs.mkdir(this.hostDir, { recursive: true });\n const snapPath = path.join(this.hostDir, SNAPSHOT_NAME);\n const tmpPath = path.join(this.hostDir, SNAPSHOT_TMP);\n\n // Drop any leftover staging file from a prior crashed write.\n await fs.rm(tmpPath, { force: true });\n\n const memFs = this.pg!.Module.FS as MemFs;\n\n if (await fileExists(snapPath)) {\n const bytes = await fs.readFile(snapPath);\n restoreMemfs(memFs, PGDATA, bytes);\n return;\n }\n\n const legacyMarker = path.join(this.hostDir, \"PG_VERSION\");\n if (await fileExists(legacyMarker)) {\n this.logger?.warn(\n `Migrating legacy PGLite data dir at ${this.hostDir} to atomic snapshot. Original files retained alongside snapshot.bin as a backup; remove them once the new snapshot is verified.`,\n );\n await loadLegacyIntoMemfs(memFs, PGDATA, this.hostDir);\n return;\n }\n }\n\n async syncToFs(relaxedDurability?: boolean): Promise<void> {\n if (this.flushIntervalMs === 0) {\n await this.writeSnapshot(relaxedDurability ?? false);\n return;\n }\n this.dirty = true;\n this.scheduleDeferredFlush(relaxedDurability ?? false);\n }\n\n async closeFs(): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n while (this.flushInFlight) {\n await this.flushInFlight;\n }\n this.dirty = false;\n await this.writeSnapshot(false);\n await super.closeFs();\n }\n\n private scheduleDeferredFlush(relaxedDurability: boolean): void {\n if (this.flushTimer || this.flushInFlight) return;\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined;\n this.flushInFlight = this.drainDirty(relaxedDurability)\n .catch((err) => {\n this.logger?.warn(\n `AtomicNodeFs deferred flush failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n })\n .finally(() => {\n this.flushInFlight = undefined;\n });\n }, this.flushIntervalMs);\n // Don't keep the event loop alive solely for a pending flush; closeFs is\n // responsible for draining before shutdown.\n this.flushTimer.unref?.();\n }\n\n private async drainDirty(relaxedDurability: boolean): Promise<void> {\n while (this.dirty) {\n this.dirty = false;\n await this.writeSnapshot(relaxedDurability);\n }\n }\n\n private async writeSnapshot(relaxedDurability: boolean): Promise<void> {\n const memFs = this.pg!.Module.FS as MemFs;\n const bytes = serializeMemfs(memFs, PGDATA);\n const snapPath = path.join(this.hostDir, SNAPSHOT_NAME);\n const tmpPath = path.join(this.hostDir, SNAPSHOT_TMP);\n\n const fh = await fs.open(tmpPath, \"w\");\n try {\n await fh.write(bytes);\n if (!relaxedDurability) await fh.sync();\n } finally {\n await fh.close();\n }\n\n await fs.rename(tmpPath, snapPath);\n\n if (!relaxedDurability) {\n try {\n const dirFh = await fs.open(this.hostDir, \"r\");\n try {\n await dirFh.sync();\n } finally {\n await dirFh.close();\n }\n } catch {\n // Some platforms reject fsync on a directory fd. The rename itself is\n // still atomic at the inode level; durability of the directory entry\n // is best-effort.\n }\n }\n }\n}\n\nfunction normalizeOptions(\n optionsOrLogger: AtomicNodeFsOptions | AtomicNodeFsLogger | undefined,\n): AtomicNodeFsOptions {\n if (!optionsOrLogger) return {};\n if (isLogger(optionsOrLogger)) {\n return { logger: optionsOrLogger };\n }\n return optionsOrLogger;\n}\n\nfunction isLogger(\n value: AtomicNodeFsOptions | AtomicNodeFsLogger,\n): value is AtomicNodeFsLogger {\n return (\n \"warn\" in value && typeof (value as AtomicNodeFsLogger).warn === \"function\"\n );\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction ensureDir(FS: MemFs, dir: string): void {\n const parts = dir.split(\"/\").filter(Boolean);\n let cur = \"\";\n for (const p of parts) {\n cur += \"/\" + p;\n if (!FS.analyzePath(cur).exists) FS.mkdir(cur);\n }\n}\n\ninterface Entry {\n type: EntryType;\n mode: number;\n relPath: string;\n data?: Uint8Array;\n}\n\nfunction serializeMemfs(FS: MemFs, root: string): Uint8Array {\n const entries: Entry[] = [];\n\n const walk = (dir: string, rel: string) => {\n const names = FS.readdir(dir);\n for (const name of names) {\n if (name === \".\" || name === \"..\") continue;\n const full = dir + \"/\" + name;\n const r = rel === \"\" ? name : rel + \"/\" + name;\n const stat = FS.stat(full);\n if (FS.isDir(stat.mode)) {\n entries.push({ type: 0, mode: stat.mode & 0o7777, relPath: r });\n walk(full, r);\n } else if (FS.isFile(stat.mode)) {\n const data = FS.readFile(full, { encoding: \"binary\" });\n entries.push({\n type: 1,\n mode: stat.mode & 0o7777,\n relPath: r,\n data,\n });\n }\n // skip symlinks, sockets, etc. — PGLite doesn't create them in PGDATA.\n }\n };\n walk(root, \"\");\n\n const encoder = new TextEncoder();\n const encodedPaths = entries.map((e) => encoder.encode(e.relPath));\n\n let size = 4 + 4 + 4; // magic + version + count\n for (let i = 0; i < entries.length; i++) {\n size += 1 + 4 + 4 + encodedPaths[i].byteLength + 4;\n size += entries[i].data?.byteLength ?? 0;\n }\n\n const out = new Uint8Array(size);\n const view = new DataView(out.buffer);\n let off = 0;\n\n out.set(MAGIC, off);\n off += 4;\n view.setUint32(off, FORMAT_VERSION, true);\n off += 4;\n view.setUint32(off, entries.length, true);\n off += 4;\n\n for (let i = 0; i < entries.length; i++) {\n const e = entries[i];\n const pathBytes = encodedPaths[i];\n view.setUint8(off, e.type);\n off += 1;\n view.setUint32(off, e.mode, true);\n off += 4;\n view.setUint32(off, pathBytes.byteLength, true);\n off += 4;\n out.set(pathBytes, off);\n off += pathBytes.byteLength;\n const dataLen = e.data?.byteLength ?? 0;\n view.setUint32(off, dataLen, true);\n off += 4;\n if (dataLen > 0 && e.data) {\n out.set(e.data, off);\n off += dataLen;\n }\n }\n\n return out;\n}\n\nfunction restoreMemfs(FS: MemFs, root: string, bytes: Uint8Array): void {\n ensureDir(FS, root);\n\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n let off = 0;\n\n for (let i = 0; i < 4; i++) {\n if (bytes[off + i] !== MAGIC[i]) {\n throw new Error(\"AtomicNodeFs: invalid snapshot magic\");\n }\n }\n off += 4;\n\n const version = view.getUint32(off, true);\n off += 4;\n if (version !== FORMAT_VERSION) {\n throw new Error(`AtomicNodeFs: unsupported snapshot version ${version}`);\n }\n const count = view.getUint32(off, true);\n off += 4;\n\n const decoder = new TextDecoder();\n\n for (let i = 0; i < count; i++) {\n const type = view.getUint8(off);\n off += 1;\n const mode = view.getUint32(off, true);\n off += 4;\n const pathLen = view.getUint32(off, true);\n off += 4;\n const relPath = decoder.decode(bytes.subarray(off, off + pathLen));\n off += pathLen;\n const dataLen = view.getUint32(off, true);\n off += 4;\n const full = root + \"/\" + relPath;\n\n if (type === 0) {\n // dirMode: a snapshot written right after a Windows migration can carry\n // execute-less directory modes, which would make it unopenable.\n if (!FS.analyzePath(full).exists) FS.mkdir(full, dirMode(mode));\n else FS.chmod(full, dirMode(mode));\n } else {\n const data = bytes.subarray(off, off + dataLen);\n FS.writeFile(full, data);\n FS.chmod(full, mode);\n }\n off += dataLen;\n }\n}\n\n/**\n * Permission bits for a directory created in MEMFS.\n *\n * Windows has no execute bit, so `fs.stat` reports every directory as 0o40666.\n * Copying that mode verbatim produces a MEMFS directory that cannot be\n * traversed, and every lookup beneath it fails with ENOENT -- which surfaces\n * as PGLite throwing a bare `ErrnoError { errno: 2 }` on the first query after\n * a legacy migration. Force the traverse bit on. MEMFS is process-local and\n * rebuilt from disk on every open, so host permissions carry no meaning here.\n */\nfunction dirMode(mode: number): number {\n return (mode & 0o7777) | 0o111;\n}\n\nasync function loadLegacyIntoMemfs(\n FS: MemFs,\n root: string,\n hostDir: string,\n): Promise<void> {\n ensureDir(FS, root);\n\n const skip = new Set([SNAPSHOT_NAME, SNAPSHOT_TMP, \"postmaster.pid\"]);\n\n const walk = async (diskPath: string, memPath: string) => {\n const ents = await fs.readdir(diskPath, { withFileTypes: true });\n for (const ent of ents) {\n if (skip.has(ent.name)) continue;\n const diskFull = path.join(diskPath, ent.name);\n const memFull = memPath + \"/\" + ent.name;\n const stat = await fs.stat(diskFull);\n if (ent.isDirectory()) {\n if (!FS.analyzePath(memFull).exists) {\n FS.mkdir(memFull, dirMode(stat.mode));\n }\n await walk(diskFull, memFull);\n } else if (ent.isFile()) {\n const data = await fs.readFile(diskFull);\n FS.writeFile(memFull, data);\n FS.chmod(memFull, stat.mode & 0o7777);\n }\n }\n };\n\n await walk(hostDir, root);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/pglite-fs",
3
- "version": "6.2.2-dev.8",
3
+ "version": "6.2.2-dev.80",
4
4
  "license": "AGPL-3.0-only",
5
5
  "type": "module",
6
6
  "repository": {