diff --git a/packages/benchmark/benchmarks-rtt.js b/packages/benchmark/benchmarks-rtt.js index 40d0eb0f..bf0bcfb2 100644 --- a/packages/benchmark/benchmarks-rtt.js +++ b/packages/benchmark/benchmarks-rtt.js @@ -15,6 +15,23 @@ const CONFIGURATIONS = new Map( db: "pglite", dataDir: "idb://benchmark-rtt", }, + { + label: "PGlite IDB
relaxed durability", + db: "pglite", + dataDir: "idb://benchmark-rtt-rd", + options: { relaxedDurability: true }, + }, + { + label: "PGlite OPFS AHP", + db: "pglite", + dataDir: "opfs-ahp://benchmark-rtt", + }, + { + label: "PGlite OPFS AHP
relaxed durability", + db: "pglite", + dataDir: "opfs-ahp://benchmark-rtt-rd", + options: { relaxedDurability: true }, + }, { label: 'SQLite Memory', db: 'wa-sqlite', @@ -39,6 +56,14 @@ const CONFIGURATIONS = new Map( vfsClass: 'OriginPrivateFileSystemVFS', vfsArgs: [] }, + { + label: 'SQLite OPFS AHP', + db: 'wa-sqlite', + isAsync: false, + vfsModule: './node_modules/wa-sqlite/src/examples/AccessHandlePoolVFS.js', + vfsClass: 'AccessHandlePoolVFS', + vfsArgs: ['/benchmark-rtt-sqlite-ahp'] + }, ].map((obj) => [obj.label, obj]) ); @@ -107,7 +132,11 @@ document.getElementById("start").addEventListener("click", async (event) => { // Remove OPFS const root = await navigator.storage.getDirectory(); for await (const handle of root.values()) { - await root.removeEntry(handle.name, { recursive: true }); + try { + await root.removeEntry(handle.name, { recursive: true }); + } catch (e) { + // ignore + } } const Comlink = await ComlinkReady; @@ -170,6 +199,6 @@ document.getElementById("start").addEventListener("click", async (event) => { function addEntry(parent, text) { const tag = parent.parentElement.tagName === "TBODY" ? "td" : "th"; const child = document.createElement(tag); - child.textContent = text; + child.innerHTML = text; parent.appendChild(child); } diff --git a/packages/benchmark/benchmarks.js b/packages/benchmark/benchmarks.js index c4889111..96673f30 100644 --- a/packages/benchmark/benchmarks.js +++ b/packages/benchmark/benchmarks.js @@ -18,6 +18,24 @@ const CONFIGURATIONS = new Map( label: "Emscripten IndexedDB FS", dataDir: "idb://benchmark", }, + { + label: "Emscripten IndexedDB FS
relaxed durability", + dataDir: "idb://benchmark-rd", + options: { relaxedDurability: true }, + }, + { + label: "OPFS Access Handle Pool", + dataDir: "opfs-ahp://benchmark-ahp", + }, + { + label: "OPFS Access Handle Pool
relaxed durability", + dataDir: "opfs-ahp://benchmark-ahp-rd", + options: { relaxedDurability: true }, + }, + // { + // label: "OPFS Worker", + // dataDir: "opfs-worker://benchmark-worker", + // }, ].map((obj) => [obj.label, obj]) ); @@ -77,6 +95,16 @@ document.getElementById("start").addEventListener("click", async (event) => { } }); + // Remove OPFS + const root = await navigator.storage.getDirectory(); + for await (const handle of root.values()) { + try { + await root.removeEntry(handle.name, { recursive: true }); + } catch (e) { + // ignore + } + } + const benchmarks = await benchmarksReady; const Comlink = await ComlinkReady; try { @@ -101,6 +129,7 @@ document.getElementById("start").addEventListener("click", async (event) => { const query = await workerProxy({ dataDir: config.dataDir, label: config.label, + options: config.options, }); await query(preamble); @@ -123,6 +152,7 @@ document.getElementById("start").addEventListener("click", async (event) => { document.getElementById("error").textContent = e.stack.includes(e.message) ? e.stack : `${e.stack}\n${e.message}`; + throw e; } finally { // @ts-ignore event.target.disabled = false; @@ -132,6 +162,6 @@ document.getElementById("start").addEventListener("click", async (event) => { function addEntry(parent, text) { const tag = parent.parentElement.tagName === "TBODY" ? "td" : "th"; const child = document.createElement(tag); - child.textContent = text; + child.innerHTML = text; parent.appendChild(child); } diff --git a/packages/benchmark/demo-worker.js b/packages/benchmark/demo-worker.js index 3ecac0e5..1df1e830 100644 --- a/packages/benchmark/demo-worker.js +++ b/packages/benchmark/demo-worker.js @@ -14,7 +14,20 @@ import { PGlite } from "../pglite/dist/index.js"; * @returns {Promise} */ async function open(config) { - const pg = new PGlite(config.dataDir); + if (config.dataDir.startsWith("opfs-")) { + // delete the existing database + const root = await navigator.storage.getDirectory(); + const dirName = config.dataDir.slice(config.dataDir.indexOf("://") + 3); + try { + const dir = await root.getDirectoryHandle(dirName, { create: false }); + await dir.remove(); + } catch (e) { + // ignore + } + } + + console.log("Opening PGLite database:", JSON.stringify(config, null, 2)); + const pg = new PGlite(config.dataDir, config.options); await pg.waitReady; // Create the query interface. diff --git a/packages/benchmark/package.json b/packages/benchmark/package.json index bcfbe9cc..99ab9c34 100644 --- a/packages/benchmark/package.json +++ b/packages/benchmark/package.json @@ -18,6 +18,6 @@ "tsx": "^4.7.1" }, "dependencies": { - "wa-sqlite": "github:rhashimoto/wa-sqlite" + "wa-sqlite": "github:rhashimoto/wa-sqlite#v0.9.14" } } diff --git a/packages/benchmark/rtt-demo-worker.js b/packages/benchmark/rtt-demo-worker.js index 4deb7875..c7d7af38 100644 --- a/packages/benchmark/rtt-demo-worker.js +++ b/packages/benchmark/rtt-demo-worker.js @@ -4,7 +4,7 @@ import * as SQLite from './node_modules/wa-sqlite/src/sqlite-api.js'; import { createTag } from "./node_modules/wa-sqlite/src/examples/tag.js"; -import { PGlite } from "../pglite/dist/index.js"; +import { PGlite } from "../pglite/dist/index.js?1"; const WA_SQLITE = './node_modules/wa-sqlite/dist/wa-sqlite.mjs'; const WA_SQLITE_ASYNC = './node_modules/wa-sqlite/dist/wa-sqlite-async.mjs'; @@ -15,18 +15,17 @@ const WA_SQLITE_ASYNC = './node_modules/wa-sqlite/dist/wa-sqlite-async.mjs'; ); async function open(config) { - console.log('Opening database:', config) if (config.db === 'wa-sqlite') { - console.log('Opening SQLite database:', config) + console.log('Opening SQLite database:', JSON.stringify(config, null, 2)) return openSQLite(config); } else if (config.db === 'pglite') { - console.log('Opening PGLite database:', config) + console.log('Opening PGLite database:', JSON.stringify(config, null, 2)) return openPGlite(config); } } async function openPGlite(config) { - const pg = new PGlite(config.dataDir); + const pg = new PGlite(config.dataDir, config.options); await pg.waitReady; // Create the query interface. diff --git a/packages/pglite/examples/opfs-worker.js b/packages/pglite/examples/opfs-worker.js new file mode 100644 index 00000000..9d03d3d3 --- /dev/null +++ b/packages/pglite/examples/opfs-worker.js @@ -0,0 +1,12 @@ +import { PGlite } from "../dist/index.js"; +import { worker } from "../dist/worker/index.js"; + +worker({ + async init() { + const pg = new PGlite("opfs-ahp://my-test-db2"); + // If you want run any specific setup code for the worker process, you can do it here. + return pg; + }, +}); + +console.log("Worker process started"); diff --git a/packages/pglite/examples/opfs.html b/packages/pglite/examples/opfs.html new file mode 100644 index 00000000..cf3cb6a1 --- /dev/null +++ b/packages/pglite/examples/opfs.html @@ -0,0 +1,49 @@ + diff --git a/packages/pglite/package.json b/packages/pglite/package.json index 990270c7..dc2aa804 100644 --- a/packages/pglite/package.json +++ b/packages/pglite/package.json @@ -21,15 +21,26 @@ ".": "./dist/index.js", "./live": "./dist/live/index.js", "./worker": "./dist/worker/index.js", - "./vector": "./dist/vector/index.js" + "./vector": "./dist/vector/index.js", + "./nodefs": "./dist/fs/nodefs.js", + "./opfs-ahp": "./dist/fs/opfs-ahp/index.js" }, "typesVersions": { "*": { + "live": [ + "./dist/live/index.d.ts" + ], "worker": [ "./dist/worker/index.d.ts" ], "vector": [ "./dist/vector/index.d.ts" + ], + "nodefs": [ + "./dist/fs/nodefs.d.ts" + ], + "opfs-ahp": [ + "./dist/fs/opfs-ahp/index.d.ts" ] } }, @@ -49,6 +60,8 @@ "test:bun": "rm -rf ./pgdata-test && npx bun test tests/basic.test.js && npx bun test tests/pgvector.test.js && npx bun test tests/targets/node-fs.test.js", "build:js": "tsup && tsx scripts/bundle-wasm.ts", "build": "npm run build:js", + "dev": "concurrently \"tsup --watch\" \"sleep 1 && tsx scripts/bundle-wasm.ts\" \"pnpm dev-server\"", + "dev-server": "pnpm http-server ../", "format": "prettier --write ./src" }, "devDependencies": { @@ -64,8 +77,9 @@ "pg-protocol": "^1.6.1", "playwright": "^1.42.1", "prettier": "3.2.5", + "serve": "^14.2.3", "tinytar": "^0.1.0", - "tsup": "^8.0.2", + "tsup": "^8.1.0", "tsx": "^4.7.1", "typescript": "^5.3.3" } diff --git a/packages/pglite/src/fs/idbfs.ts b/packages/pglite/src/fs/idbfs.ts index 4965c92e..6b62510d 100644 --- a/packages/pglite/src/fs/idbfs.ts +++ b/packages/pglite/src/fs/idbfs.ts @@ -38,7 +38,7 @@ export class IdbFs extends FilesystemBase { }); } - syncToFs(fs: FS) { + syncToFs(fs: FS, relaxedDurability?: boolean) { return new Promise((resolve, reject) => { fs.syncfs(false, (err: any) => { if (err) { diff --git a/packages/pglite/src/fs/index.ts b/packages/pglite/src/fs/index.ts index 0dfd5423..ebe8844a 100644 --- a/packages/pglite/src/fs/index.ts +++ b/packages/pglite/src/fs/index.ts @@ -20,6 +20,10 @@ export function parseDataDir(dataDir?: string) { // Remove the idb:// prefix, and use indexeddb filesystem dataDir = dataDir.slice(6); fsType = "idbfs"; + } else if (dataDir?.startsWith("opfs-ahp://")) { + // Remove the opfsahp:// prefix, and use opfs access handle pool filesystem + dataDir = dataDir.slice(11); + fsType = "opfs-ahp"; } else if (!dataDir || dataDir?.startsWith("memory://")) { // Use in-memory filesystem fsType = "memoryfs"; @@ -38,6 +42,10 @@ export async function loadFs(dataDir?: string, fsType?: FsType) { fs = new NodeFS(dataDir); } else if (dataDir && fsType === "idbfs") { fs = new IdbFs(dataDir); + } else if (dataDir && fsType === "opfs-ahp") { + // Lazy load the opfs-ahp to so that it's optional in the bundle + const { OpfsAhpFS } = await import("./opfs-ahp/index.js"); + fs = new OpfsAhpFS(dataDir); } else { fs = new MemoryFS(); } diff --git a/packages/pglite/src/fs/opfs-ahp/emscriptenFs.ts b/packages/pglite/src/fs/opfs-ahp/emscriptenFs.ts new file mode 100644 index 00000000..ab168b3d --- /dev/null +++ b/packages/pglite/src/fs/opfs-ahp/emscriptenFs.ts @@ -0,0 +1,371 @@ +import type { PostgresMod } from "../../postgresMod.js"; +import type { OpfsAhp } from "./opfsAhp.js"; +import { FsError, ERRNO_CODES } from "./types.js"; + +export type FileSystemType = Emscripten.FileSystemType & { + createNode: ( + parent: FSNode | null, + name: string, + mode: number, + dev?: any, + ) => FSNode; + node_ops: FS.NodeOps; + stream_ops: FS.StreamOps & { + dup: (stream: FSStream) => void; + mmap: ( + stream: FSStream, + length: number, + position: number, + prot: any, + flags: any, + ) => { ptr: number; allocated: boolean }; + msync: ( + stream: FSStream, + buffer: Uint8Array, + offset: number, + length: number, + mmapFlags: any, + ) => number; + }; +} & { [key: string]: any }; + +type FSNode = FS.FSNode & { + node_ops: FS.NodeOps; + stream_ops: FS.StreamOps; +}; + +type FSStream = FS.FSStream & { + node: FSNode; + shared: { + refcount: number; + }; +}; + +export interface OpfsMount extends FS.Mount { + opts: { + root: string; + }; +} + +type OpfsNode = FSNode & {}; + +type EmscriptenFS = PostgresMod["FS"] & { + createNode: ( + parent: FSNode | null, + name: string, + mode: number, + dev?: any, + ) => FSNode; +}; + +/** + * Create an emscripten filesystem that uses the AHP filesystem. + * @param Module The emscripten module + * @param opfsAhp The AHP filesystem - see `OpfsAhp.ts` + * @returns The emscripten filesystem + */ +export const createOPFSAHP = (Module: PostgresMod, opfsAhp: OpfsAhp) => { + const FS = Module.FS as EmscriptenFS; + const OPFS = { + tryFSOperation(f: () => T): T { + try { + return f(); + } catch (e: any) { + if (!e.code) throw e; + if (e.code === "UNKNOWN") throw new FS.ErrnoError(ERRNO_CODES.EINVAL); + throw new FS.ErrnoError(e.code); + } + }, + mount(mount: OpfsMount): FSNode { + return OPFS.createNode(null, "/", 16384 | 511, 0); + }, + syncfs( + mount: FS.Mount, + populate: any, // This has the wrong type in @types/emscripten + done: (err?: number | null) => unknown, + ): void { + // noop + }, + createNode( + parent: FSNode | null, + name: string, + mode: number, + dev?: any, + ): OpfsNode { + if (!FS.isDir(mode) && !FS.isFile(mode)) { + throw new FS.ErrnoError(28); + } + const node = FS.createNode(parent, name, mode); + node.node_ops = OPFS.node_ops; + node.stream_ops = OPFS.stream_ops; + return node; + }, + getMode: function (path: string): number { + log("getMode", path); + return OPFS.tryFSOperation(() => { + const stats = opfsAhp.lstat(path); + return stats.mode; + }); + }, + realPath: function (node: FSNode): string { + const parts = []; + while (node.parent !== node) { + parts.push(node.name); + node = node.parent as FSNode; + } + parts.push((node.mount as OpfsMount).opts.root); + parts.reverse(); + return parts.join("/"); + }, + node_ops: { + getattr(node: OpfsNode): FS.Stats { + log("getattr", OPFS.realPath(node)); + const path = OPFS.realPath(node); + return OPFS.tryFSOperation(() => { + const stats = opfsAhp.lstat(path); + return { + ...stats, + dev: 0, + ino: node.id, + nlink: 1, + rdev: node.rdev, + atime: new Date(stats.atime), + mtime: new Date(stats.mtime), + ctime: new Date(stats.ctime), + }; + }); + }, + setattr(node: OpfsNode, attr: FS.Stats): void { + log("setattr", OPFS.realPath(node), attr); + var path = OPFS.realPath(node); + OPFS.tryFSOperation(() => { + if (attr.mode !== undefined) { + opfsAhp.chmod(path, attr.mode); + } + if (attr.size !== undefined) { + opfsAhp.truncate(path, attr.size); + } + if (attr.timestamp !== undefined) { + opfsAhp.utimes(path, attr.timestamp, attr.timestamp); + } + if (attr.size !== undefined) { + opfsAhp.truncate(path, attr.size); + } + }); + }, + lookup(parent: FSNode, name: string): OpfsNode { + log("lookup", OPFS.realPath(parent), name); + const path = [OPFS.realPath(parent), name].join("/"); + const mode = OPFS.getMode(path); + return OPFS.createNode(parent, name, mode); + }, + mknod( + parent: FSNode, + name: string, + mode: number, + dev: unknown, + ): OpfsNode { + log("mknod", OPFS.realPath(parent), name, mode, dev); + const node = OPFS.createNode(parent, name, mode, dev); + // create the backing node for this in the fs root as well + const path = OPFS.realPath(node); + return OPFS.tryFSOperation(() => { + if (FS.isDir(node.mode)) { + opfsAhp.mkdir(path, { mode }); + } else { + opfsAhp.writeFile(path, "", { mode }); + } + return node; + }); + }, + rename(oldNode: OpfsNode, newDir: OpfsNode, newName: string): void { + log("rename", OPFS.realPath(oldNode), OPFS.realPath(newDir), newName); + const oldPath = OPFS.realPath(oldNode); + const newPath = [OPFS.realPath(newDir), newName].join("/"); + OPFS.tryFSOperation(() => { + opfsAhp.rename(oldPath, newPath); + }); + oldNode.name = newName; + }, + unlink(parent: OpfsNode, name: string): void { + log("unlink", OPFS.realPath(parent), name); + const path = [OPFS.realPath(parent), name].join("/"); + try { + opfsAhp.unlink(path); + } catch (e: any) {} + }, + rmdir(parent: OpfsNode, name: string): void { + log("rmdir", OPFS.realPath(parent), name); + const path = [OPFS.realPath(parent), name].join("/"); + return OPFS.tryFSOperation(() => { + opfsAhp.rmdir(path); + }); + }, + readdir(node: OpfsNode): string[] { + log("readdir", OPFS.realPath(node)); + const path = OPFS.realPath(node); + return OPFS.tryFSOperation(() => { + return opfsAhp.readdir(path); + }); + }, + symlink(parent: FSNode, newName: string, oldPath: string): void { + log("symlink", OPFS.realPath(parent), newName, oldPath); + // This is not supported by OPFS + throw new FS.ErrnoError(63); + }, + readlink(node: FSNode): string { + log("readlink", OPFS.realPath(node)); + // This is not supported by OPFS + throw new FS.ErrnoError(63); + }, + }, + stream_ops: { + open(stream: FSStream): void { + log("open stream", OPFS.realPath(stream.node)); + const path = OPFS.realPath(stream.node); + return OPFS.tryFSOperation(() => { + if (FS.isFile(stream.node.mode)) { + stream.shared.refcount = 1; + stream.nfd = opfsAhp.open(path); + } + }); + }, + close(stream: FSStream): void { + log("close stream", OPFS.realPath(stream.node)); + return OPFS.tryFSOperation(() => { + if ( + FS.isFile(stream.node.mode) && + stream.nfd && + --stream.shared.refcount === 0 + ) { + opfsAhp.close(stream.nfd); + } + }); + }, + dup(stream: FSStream) { + log("dup stream", OPFS.realPath(stream.node)); + stream.shared.refcount++; + }, + read( + stream: FSStream, // Stream to read from + buffer: Uint8Array, // Buffer to read into - Wrong type in @types/emscripten + offset: number, // Offset in buffer to start writing to + length: number, // Number of bytes to read + position: number, // Position in file to read from + ): number { + log( + "read stream", + OPFS.realPath(stream.node), + offset, + length, + position, + ); + if (length === 0) return 0; + const ret = OPFS.tryFSOperation(() => + opfsAhp.read( + stream.nfd!, + buffer as unknown as Int8Array, + offset, + length, + position, + ), + ); + return ret; + }, + write( + stream: FSStream, // Stream to write to + buffer: Uint8Array, // Buffer to read from - Wrong type in @types/emscripten + offset: number, // Offset in buffer to start writing from + length: number, // Number of bytes to write + position: number, // Position in file to write to + ): number { + log( + "write stream", + OPFS.realPath(stream.node), + offset, + length, + position, + ); + return OPFS.tryFSOperation(() => + opfsAhp.write( + stream.nfd!, + buffer.buffer as unknown as Int8Array, + offset, + length, + position, + ), + ); + }, + llseek(stream: FSStream, offset: number, whence: number): number { + log("llseek stream", OPFS.realPath(stream.node), offset, whence); + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + OPFS.tryFSOperation(() => { + var stat = opfsAhp.fstat(stream.nfd!); + position += stat.size; + }); + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + mmap( + stream: FSStream, + length: number, + position: number, + prot: any, + flags: any, + ) { + log( + "mmap stream", + OPFS.realPath(stream.node), + length, + position, + prot, + flags, + ); + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(ERRNO_CODES.ENODEV); + } + + var ptr = (Module as any).mmapAlloc(length); // TODO: Fix type and check this is exported + + OPFS.stream_ops.read( + stream, + Module.HEAP8 as unknown as Uint8Array, + ptr, + length, + position, + ); + return { ptr, allocated: true }; + }, + msync( + stream: FSStream, + buffer: Uint8Array, + offset: number, + length: number, + mmapFlags: any, + ) { + log( + "msync stream", + OPFS.realPath(stream.node), + offset, + length, + mmapFlags, + ); + OPFS.stream_ops.write(stream, buffer, 0, length, offset); + return 0; + }, + }, + } satisfies FileSystemType; + return OPFS; +}; + +function log(...args: any[]) { + // console.log(...args); +} diff --git a/packages/pglite/src/fs/opfs-ahp/index.ts b/packages/pglite/src/fs/opfs-ahp/index.ts new file mode 100644 index 00000000..a4dee6c3 --- /dev/null +++ b/packages/pglite/src/fs/opfs-ahp/index.ts @@ -0,0 +1,67 @@ +import { FilesystemBase } from "../types.js"; +import { PGDATA } from "../index.js"; +import type { PostgresMod, FS } from "../../postgresMod.js"; +import { createOPFSAHP } from "./emscriptenFs.js"; +import { OpfsAhp } from "./opfsAhp.js"; +import { dumpTar } from "../tarUtils.js"; + +export interface OpfsAhpFSOptions { + initialPoolSize?: number; + maintainedPoolSize?: number; +} + +/** + * PGlite OPFS access handle pool filesystem. + * Opens a pool of sync access handles and then allocates them as needed. + */ +export class OpfsAhpFS extends FilesystemBase { + #initialPoolSize: number; + #maintainedPoolSize: number; + opfsAhp?: OpfsAhp; + + constructor( + dataDir: string, + { initialPoolSize, maintainedPoolSize }: OpfsAhpFSOptions = {}, + ) { + super(dataDir); + this.#initialPoolSize = initialPoolSize ?? 1000; + this.#maintainedPoolSize = maintainedPoolSize ?? 100; + } + + async emscriptenOpts(opts: Partial) { + this.opfsAhp = await OpfsAhp.create({ + root: this.dataDir!, + initialPoolSize: this.#initialPoolSize, + maintainedPoolSize: this.#maintainedPoolSize, + }); + const options: Partial = { + ...opts, + preRun: [ + ...(opts.preRun || []), + (mod: PostgresMod) => { + const OPFS = createOPFSAHP(mod, this.opfsAhp!); + mod.FS.mkdir(PGDATA); + mod.FS.mount(OPFS, {}, PGDATA); + }, + ], + }; + return options; + } + + async syncToFs(fs: FS, relaxedDurability = false) { + await this.opfsAhp?.maybeCheckpointState(); + await this.opfsAhp?.maintainPool(); + // console.log("syncToFs", relaxedDurability); + if (!relaxedDurability) { + this.opfsAhp?.flush(); + } + } + + async dumpTar(mod: FS, dbname: string) { + return dumpTar(mod, dbname); + } + + async close(): Promise { + this.opfsAhp?.exit(); + } +} diff --git a/packages/pglite/src/fs/opfs-ahp/opfsAhp.ts b/packages/pglite/src/fs/opfs-ahp/opfsAhp.ts new file mode 100644 index 00000000..2af10555 --- /dev/null +++ b/packages/pglite/src/fs/opfs-ahp/opfsAhp.ts @@ -0,0 +1,670 @@ +import { FsError } from "./types.js"; +import type { + FsStats, + State, + FileSystemSyncAccessHandle, + Node, + FileNode, + DirectoryNode, + WALEntry, +} from "./types.js"; + +const STATE_FILE = "state.txt"; +const DATA_DIR = "data"; +const INITIAL_MODE = { + DIR: 16384, + FILE: 32768, +}; + +export interface OpfsAhpOptions { + root: string; + initialPoolSize?: number; + maintainedPoolSize?: number; +} + +/** + * An OPFS Access Handle Pool VFS that exports a Node.js-like FS interface. + * This FS is then wrapped by an Emscripten FS interface in emscriptenFs.ts. + */ +export class OpfsAhp { + readyPromise: Promise; + #ready = false; + + readonly root: string; + readonly initialPoolSize: number; + readonly maintainedPoolSize: number; + + #opfsRootAh!: FileSystemDirectoryHandle; + #rootAh!: FileSystemDirectoryHandle; + #dataDirAh!: FileSystemDirectoryHandle; + + #stateFH!: FileSystemFileHandle; + #stateSH!: FileSystemSyncAccessHandle; + + #fh: Map = new Map(); + #sh: Map = new Map(); + + #handleIdCounter = 0; + #openHandlePaths: Map = new Map(); + #openHandleIds: Map = new Map(); + + state!: State; + lastCheckpoint = 0; + checkpointInterval = 1000 * 60; // 1 minute + poolCounter = 0; + + #unsyncedSH = new Set(); + + constructor({ root, initialPoolSize, maintainedPoolSize }: OpfsAhpOptions) { + this.root = root; + this.initialPoolSize = initialPoolSize || 1000; + this.maintainedPoolSize = maintainedPoolSize || 100; + this.readyPromise = this.#init(); + } + + static async create(options: OpfsAhpOptions) { + const instance = new OpfsAhp(options); + await instance.readyPromise; + return instance; + } + + async #init() { + this.#opfsRootAh = await navigator.storage.getDirectory(); + this.#rootAh = await this.#resolveOpfsDirectory(this.root, { + create: true, + }); + this.#dataDirAh = await this.#resolveOpfsDirectory(DATA_DIR, { + from: this.#rootAh, + create: true, + }); + + this.#stateFH = await this.#rootAh.getFileHandle(STATE_FILE, { + create: true, + }); + this.#stateSH = await (this.#stateFH as any).createSyncAccessHandle(); + + const stateAB = new ArrayBuffer(this.#stateSH.getSize()); + this.#stateSH.read(stateAB, { at: 0 }); + let state: State; + const stateLines = new TextDecoder().decode(stateAB).split("\n"); + // Line 1 is a base state object. + // Lines 1+n are WAL entries. + + let isNewState = false; + try { + state = JSON.parse(stateLines[0]); + } catch (e) { + state = { + root: { + type: "directory", + lastModified: Date.now(), + mode: INITIAL_MODE.DIR, + children: {}, + }, + pool: [], + }; + // write new state to file + this.#stateSH.truncate(0); + this.#stateSH.write(new TextEncoder().encode(JSON.stringify(state)), { + at: 0, + }); + isNewState = true; + } + this.state = state; + + // Apply WAL entries + const wal = stateLines + .slice(1) + .filter(Boolean) + .map((line) => JSON.parse(line)); + for (const entry of wal) { + const methodName = `_${entry.opp}State`; + if (typeof this[methodName as keyof this] === "function") { + try { + (this[methodName as keyof this] as any)(...entry.args); + } catch (e) { + console.warn("Error applying OPFS AHP WAL entry", entry, e); + } + } + } + + // Open all file handles for dir tree + const walkPromises: Promise[] = []; + const walk = async (node: Node) => { + if (node.type === "file") { + try { + const fh = await this.#dataDirAh.getFileHandle(node.backingFilename); + const sh: FileSystemSyncAccessHandle = await ( + fh as any + ).createSyncAccessHandle(); + this.#fh.set(node.backingFilename, fh); + + this.#sh.set(node.backingFilename, sh); + } catch (e) { + console.error("Error opening file handle for node", node, e); + } + } else { + for (const child of Object.values(node.children)) { + walkPromises.push(walk(child)); + } + } + }; + await walk(this.state.root); + + // Open all pool file handles + const poolPromises: Promise[] = []; + for (const filename of this.state.pool) { + poolPromises.push( + new Promise(async (resolve) => { + if (this.#fh.has(filename)) { + console.warn("File handle already exists for pool file", filename); + } + const fh = await this.#dataDirAh.getFileHandle(filename); + const sh: FileSystemSyncAccessHandle = await ( + fh as any + ).createSyncAccessHandle(); + this.#fh.set(filename, fh); + this.#sh.set(filename, sh); + resolve(); + }), + ); + } + + await Promise.all([...walkPromises, ...poolPromises]); + + await this.maintainPool( + isNewState ? this.initialPoolSize : this.maintainedPoolSize, + ); + + this.#ready = true; + } + + get ready() { + return this.#ready; + } + + async maintainPool(size?: number) { + size = size || this.maintainedPoolSize; + const change = size - this.state.pool.length; + const promises: Promise[] = []; + for (let i = 0; i < change; i++) { + promises.push( + new Promise(async (resolve) => { + ++this.poolCounter; + const filename = `${(Date.now() - 1704063600).toString(16).padStart(8, "0")}-${this.poolCounter.toString(16).padStart(8, "0")}`; + const fh = await this.#dataDirAh.getFileHandle(filename, { + create: true, + }); + const sh: FileSystemSyncAccessHandle = await ( + fh as any + ).createSyncAccessHandle(); + this.#fh.set(filename, fh); + this.#sh.set(filename, sh); + this.#logWAL({ + opp: "createPoolFile", + args: [filename], + }); + this.state.pool.push(filename); + resolve(); + }), + ); + } + for (let i = 0; i > change; i--) { + promises.push( + new Promise(async (resolve) => { + const filename = this.state.pool.pop()!; + this.#logWAL({ + opp: "deletePoolFile", + args: [filename], + }); + const fh = this.#fh.get(filename)!; + const sh = this.#sh.get(filename); + sh?.close(); + // @ts-ignore + await fh.remove(); + this.#fh.delete(filename); + this.#sh.delete(filename); + resolve(); + }), + ); + } + await Promise.all(promises); + } + + _createPoolFileState(filename: string) { + this.state.pool.push(filename); + } + + _deletePoolFileState(filename: string) { + const index = this.state.pool.indexOf(filename); + if (index > -1) { + this.state.pool.splice(index, 1); + } + } + + async maybeCheckpointState() { + if (Date.now() - this.lastCheckpoint > this.checkpointInterval) { + await this.checkpointState(); + } + } + + async checkpointState() { + const stateAB = new TextEncoder().encode(JSON.stringify(this.state)); + this.#stateSH.truncate(0); + this.#stateSH.write(stateAB, { at: 0 }); + this.#stateSH.flush(); + this.lastCheckpoint = Date.now(); + } + + flush() { + for (const sh of this.#unsyncedSH) { + try { + sh.flush(); + } catch (e) {} // The file may have been closed if it was deleted + } + this.#unsyncedSH.clear(); + } + + exit(): void { + for (const sh of this.#sh.values()) { + sh.close(); + } + this.#stateSH.flush(); + this.#stateSH.close(); + } + + // Filesystem API: + + chmod(path: string, mode: number): void { + this.#tryWithWAL({ opp: "chmod", args: [path, mode] }, () => { + this._chmodState(path, mode); + }); + } + + _chmodState(path: string, mode: number): void { + const node = this.#resolvePath(path); + node.mode = mode; + } + + close(fd: number): void { + const path = this.#getPathFromFd(fd); + this.#openHandlePaths.delete(fd); + this.#openHandleIds.delete(path); + } + + fstat(fd: number): FsStats { + const path = this.#getPathFromFd(fd); + return this.lstat(path); + } + + lstat(path: string): FsStats { + const node = this.#resolvePath(path); + const size = + node.type === "file" ? this.#sh.get(node.backingFilename)!.getSize() : 0; + const blksize = 4096; + return { + dev: 0, + ino: 0, + mode: node.mode, + nlink: 1, + uid: 0, + gid: 0, + rdev: 0, + size, + blksize, + blocks: Math.ceil(size / blksize), + atime: node.lastModified, + mtime: node.lastModified, + ctime: node.lastModified, + }; + } + + mkdir(path: string, options?: { recursive?: boolean; mode?: number }): void { + this.#tryWithWAL({ opp: "mkdir", args: [path, options] }, () => { + this._mkdirState(path, options); + }); + } + + _mkdirState( + path: string, + options?: { recursive?: boolean; mode?: number }, + ): void { + const parts = this.#pathParts(path); + const newDirName = parts.pop()!; + let currentPath = []; + let node = this.state.root; + for (const part of parts) { + currentPath.push(path); + if (!node.children.hasOwnProperty(part)) { + if (options?.recursive) { + this.mkdir(currentPath.join("/")); + } else { + throw new FsError("ENOENT", "No such file or directory"); + } + } + if (node.children[part].type !== "directory") { + throw new FsError("ENOTDIR", "Not a directory"); + } + node = node.children[part] as DirectoryNode; + } + if (node.children.hasOwnProperty(newDirName)) { + throw new FsError("EEXIST", "File exists"); + } + const newDir: DirectoryNode = { + type: "directory", + lastModified: Date.now(), + mode: options?.mode || INITIAL_MODE.DIR, + children: {}, + }; + node.children[newDirName] = newDir; + } + + open(path: string, flags?: string, mode?: number): number { + const node = this.#resolvePath(path); + if (node.type !== "file") { + throw new FsError("EISDIR", "Is a directory"); + } + const handleId = this.#nextHandleId(); + this.#openHandlePaths.set(handleId, path); + this.#openHandleIds.set(path, handleId); + return handleId; + } + + readdir(path: string): string[] { + const node = this.#resolvePath(path); + if (node.type !== "directory") { + throw new FsError("ENOTDIR", "Not a directory"); + } + return Object.keys(node.children); + } + + read( + fd: number, + buffer: Int8Array, // Buffer to read into + offset: number, // Offset in buffer to start writing to + length: number, // Number of bytes to read + position: number, // Position in file to read from + ): number { + const path = this.#getPathFromFd(fd); + const node = this.#resolvePath(path); + if (node.type !== "file") { + throw new FsError("EISDIR", "Is a directory"); + } + const sh = this.#sh.get(node.backingFilename)!; + return sh.read(new Int8Array(buffer.buffer, offset, length), { + at: position, + }); + } + + rename(oldPath: string, newPath: string): void { + this.#tryWithWAL({ opp: "rename", args: [oldPath, newPath] }, () => { + this._renameState(oldPath, newPath, true); + }); + } + + _renameState(oldPath: string, newPath: string, doFileOps = false): void { + const oldPathParts = this.#pathParts(oldPath); + const oldFilename = oldPathParts.pop()!; + const oldParent = this.#resolvePath( + oldPathParts.join("/"), + ) as DirectoryNode; + if (!oldParent.children.hasOwnProperty(oldFilename)) { + throw new FsError("ENOENT", "No such file or directory"); + } + const newPathParts = this.#pathParts(newPath); + const newFilename = newPathParts.pop()!; + const newParent = this.#resolvePath( + newPathParts.join("/"), + ) as DirectoryNode; + if (doFileOps && newParent.children.hasOwnProperty(newFilename)) { + // Overwrite, so return the underlying file to the pool + const node = newParent.children[newFilename]! as FileNode; + const sh = this.#sh.get(node.backingFilename)!; + sh.truncate(0); + this.state.pool.push(node.backingFilename); + } + newParent.children[newFilename] = oldParent.children[oldFilename]!; + delete oldParent.children[oldFilename]; + } + + rmdir(path: string): void { + this.#tryWithWAL({ opp: "rmdir", args: [path] }, () => { + this._rmdirState(path); + }); + } + + _rmdirState(path: string): void { + const pathParts = this.#pathParts(path); + const dirName = pathParts.pop()!; + const parent = this.#resolvePath(pathParts.join("/")) as DirectoryNode; + if (!parent.children.hasOwnProperty(dirName)) { + throw new FsError("ENOENT", "No such file or directory"); + } + const node = parent.children[dirName]!; + if (node.type !== "directory") { + throw new FsError("ENOTDIR", "Not a directory"); + } + if (Object.keys(node.children).length > 0) { + throw new FsError("ENOTEMPTY", "Directory not empty"); + } + delete parent.children[dirName]; + } + + truncate(path: string, len = 0): void { + const node = this.#resolvePath(path); + if (node.type !== "file") { + throw new FsError("EISDIR", "Is a directory"); + } + const sh = this.#sh.get(node.backingFilename); + if (!sh) { + throw new FsError("ENOENT", "No such file or directory"); + } + sh.truncate(len); + this.#unsyncedSH.add(sh); + } + + unlink(path: string): void { + this.#tryWithWAL({ opp: "unlink", args: [path] }, () => { + this._unlinkState(path, true); + }); + } + + _unlinkState(path: string, doFileOps = false): void { + const pathParts = this.#pathParts(path); + const filename = pathParts.pop()!; + const dir = this.#resolvePath(pathParts.join("/")) as DirectoryNode; + if (!dir.children.hasOwnProperty(filename)) { + throw new FsError("ENOENT", "No such file or directory"); + } + const node = dir.children[filename]!; + if (node.type !== "file") { + throw new FsError("EISDIR", "Is a directory"); + } + delete dir.children[filename]; + if (doFileOps) { + const sh = this.#sh.get(node.backingFilename)!; + // We don't delete the file, it's truncated and returned to the pool + sh?.truncate(0); + this.#unsyncedSH.add(sh); + if (this.#openHandleIds.has(path)) { + this.#openHandlePaths.delete(this.#openHandleIds.get(path)!); + this.#openHandleIds.delete(path); + } + } + this.state.pool.push(node.backingFilename); + } + + utimes(path: string, atime: number, mtime: number): void { + this.#tryWithWAL({ opp: "utimes", args: [path, atime, mtime] }, () => { + this._utimesState(path, atime, mtime); + }); + } + + _utimesState(path: string, atime: number, mtime: number): void { + const node = this.#resolvePath(path); + node.lastModified = mtime; + } + + writeFile( + path: string, + data: string | Int8Array, + options?: { encoding?: string; mode?: number; flag?: string }, + ): void { + const pathParts = this.#pathParts(path); + const filename = pathParts.pop()!; + const parent = this.#resolvePath(pathParts.join("/")) as DirectoryNode; + + if (!parent.children.hasOwnProperty(filename)) { + if (this.state.pool.length === 0) { + throw new Error("No more file handles available in the pool"); + } + const node: Node = { + type: "file", + lastModified: Date.now(), + mode: options?.mode || INITIAL_MODE.FILE, + backingFilename: this.state.pool.pop()!, + }; + parent.children[filename] = node; + this.#logWAL({ + opp: "createFileNode", + args: [path, node], + }); + } else { + const node = parent.children[filename] as FileNode; + node.lastModified = Date.now(); + this.#logWAL({ + opp: "setLastModified", + args: [path, node.lastModified], + }); + } + const node = parent.children[filename] as FileNode; + const sh = this.#sh.get(node.backingFilename)!; + // Files in pool are empty, only write if data is provided + if (data.length > 0) { + sh.write( + typeof data === "string" + ? new TextEncoder().encode(data) + : new Int8Array(data), + { at: 0 }, + ); + if (path.startsWith("/pg_wal")) { + this.#unsyncedSH.add(sh); + } + } + } + + _createFileNodeState(path: string, node: FileNode): FileNode { + const pathParts = this.#pathParts(path); + const filename = pathParts.pop()!; + const parent = this.#resolvePath(pathParts.join("/")) as DirectoryNode; + parent.children[filename] = node; + // remove backingFilename from pool + const index = this.state.pool.indexOf(node.backingFilename); + if (index > -1) { + this.state.pool.splice(index, 1); + } + return node; + } + + _setLastModifiedState(path: string, lastModified: number): void { + const node = this.#resolvePath(path); + node.lastModified = lastModified; + } + + write( + fd: number, + buffer: Int8Array, // Buffer to read from + offset: number, // Offset in buffer to start reading from + length: number, // Number of bytes to write + position: number, // Position in file to write to + ): number { + const path = this.#getPathFromFd(fd); + const node = this.#resolvePath(path); + if (node.type !== "file") { + throw new FsError("EISDIR", "Is a directory"); + } + const sh = this.#sh.get(node.backingFilename); + if (!sh) { + throw new FsError("EBADF", "Bad file descriptor"); + } + const ret = sh.write(new Int8Array(buffer, offset, length), { + at: position, + }); + if (path.startsWith("/pg_wal")) { + this.#unsyncedSH.add(sh); + } + return ret; + } + + // Internal methods: + + #tryWithWAL(entry: WALEntry, fn: () => void) { + const offset = this.#logWAL(entry); + try { + fn(); + } catch (e) { + // Rollback WAL entry + this.#stateSH.truncate(offset); + throw e; + } + } + + #logWAL(entry: WALEntry) { + const entryJSON = JSON.stringify(entry); + const stateAB = new TextEncoder().encode(`\n${entryJSON}`); + const offset = this.#stateSH.getSize(); + this.#stateSH.write(stateAB, { at: offset }); + this.#unsyncedSH.add(this.#stateSH); + return offset; + } + + #pathParts(path: string): string[] { + return path.split("/").filter(Boolean); + } + + #resolvePath(path: string, from?: DirectoryNode): Node { + const parts = this.#pathParts(path); + let node: Node = from || this.state.root; + for (const part of parts) { + if (node.type !== "directory") { + throw new FsError("ENOTDIR", "Not a directory"); + } + if (!node.children.hasOwnProperty(part)) { + throw new FsError("ENOENT", "No such file or directory"); + } + node = node.children[part]!; + } + return node; + } + + #getPathFromFd(fd: number): string { + const path = this.#openHandlePaths.get(fd); + if (!path) { + throw new FsError("EBADF", "Bad file descriptor"); + } + return path; + } + + #nextHandleId(): number { + const id = ++this.#handleIdCounter; + while (this.#openHandlePaths.has(id)) { + this.#handleIdCounter++; + } + return id; + } + + async #resolveOpfsDirectory( + path: string, + options?: { + from?: FileSystemDirectoryHandle; + create?: boolean; + }, + ): Promise { + const parts = this.#pathParts(path); + let ah = options?.from || this.#opfsRootAh; + for (const part of parts) { + ah = await ah.getDirectoryHandle(part, { create: options?.create }); + } + return ah; + } +} diff --git a/packages/pglite/src/fs/opfs-ahp/types.ts b/packages/pglite/src/fs/opfs-ahp/types.ts new file mode 100644 index 00000000..acc8dd4e --- /dev/null +++ b/packages/pglite/src/fs/opfs-ahp/types.ts @@ -0,0 +1,87 @@ +export type FsStats = { + dev: number; + ino: number; + mode: number; + nlink: number; + uid: number; + gid: number; + rdev: number; + size: number; + blksize: number; + blocks: number; + atime: number; + mtime: number; + ctime: number; +}; + +// TypeScript doesn't have a built-in type for FileSystemSyncAccessHandle +export interface FileSystemSyncAccessHandle { + close(): void; + flush(): void; + getSize(): number; + read(buffer: ArrayBuffer, options: { at: number }): number; + truncate(newSize: number): void; + write(buffer: ArrayBuffer, options: { at: number }): number; +} + +export const ERRNO_CODES = { + EBADF: 8, + EBADFD: 127, + EEXIST: 20, + EINVAL: 28, + EISDIR: 31, + ENODEV: 43, + ENOENT: 44, + ENOTDIR: 54, + ENOTEMPTY: 55, +} as const; + +export class FsError extends Error { + code?: number; + constructor(code: number | keyof typeof ERRNO_CODES | null, message: string) { + super(message); + if (typeof code === "number") { + this.code = code; + } else if (typeof code === "string") { + this.code = ERRNO_CODES[code]; + } + } +} + +// State + +export interface State { + root: DirectoryNode; + pool: PoolFilenames; +} + +export type PoolFilenames = Array; + +// WAL + +export interface WALEntry { + opp: string; + args: any[]; +} + +// Node tree + +export type NodeType = "file" | "directory"; + +interface BaseNode { + type: NodeType; + lastModified: number; + mode: number; +} + +export interface FileNode extends BaseNode { + type: "file"; + backingFilename: string; +} + +export interface DirectoryNode extends BaseNode { + type: "directory"; + children: { [filename: string]: Node }; +} + +export type Node = FileNode | DirectoryNode; diff --git a/packages/pglite/src/fs/types.ts b/packages/pglite/src/fs/types.ts index bef970a6..46b7aa00 100644 --- a/packages/pglite/src/fs/types.ts +++ b/packages/pglite/src/fs/types.ts @@ -1,6 +1,11 @@ import type { PostgresMod, FS } from "../postgresMod.js"; -export type FsType = "nodefs" | "idbfs" | "memoryfs"; +export type FsType = + | "nodefs" + | "idbfs" + | "memoryfs" + | "opfs-worker" + | "opfs-ahp"; export interface FilesystemFactory { new (dataDir: string): Filesystem; @@ -15,7 +20,7 @@ export interface Filesystem { /** * Sync the filesystem to the emscripten filesystem. */ - syncToFs(FS: FS): Promise; + syncToFs(mod: FS, relaxedDurability?: boolean): Promise; /** * Sync the emscripten filesystem to the filesystem. @@ -26,6 +31,11 @@ export interface Filesystem { * Dump the PGDATA dir from the filesystem to a gziped tarball. */ dumpTar(FS: FS, dbname: string): Promise; + + /** + * Close the filesystem. + */ + close(): Promise; } export abstract class FilesystemBase implements Filesystem { @@ -36,7 +46,8 @@ export abstract class FilesystemBase implements Filesystem { abstract emscriptenOpts( opts: Partial, ): Promise>; - async syncToFs(FS: FS) {} + async syncToFs(mod: FS, relaxedDurability?: boolean) {} async initialSyncFs(mod: FS) {} abstract dumpTar(mod: FS, dbname: string): Promise; + async close() {} } diff --git a/packages/pglite/src/index.ts b/packages/pglite/src/index.ts index 6be35516..85ca58a5 100644 --- a/packages/pglite/src/index.ts +++ b/packages/pglite/src/index.ts @@ -4,4 +4,6 @@ export * as types from "./types.js"; export * as parse from "./parse.js"; export * as messages from "pg-protocol/dist/messages.js"; export * as protocol from "pg-protocol/dist/index.js"; +export { MemoryFS } from "./fs/memoryfs.js"; +export { IdbFs } from "./fs/idbfs.js"; export { Mutex } from "async-mutex"; diff --git a/packages/pglite/src/pglite.ts b/packages/pglite/src/pglite.ts index 371057ff..3ce381d2 100644 --- a/packages/pglite/src/pglite.ts +++ b/packages/pglite/src/pglite.ts @@ -686,7 +686,7 @@ export class PGlite implements PGliteInterface { const doSync = async () => { await this.#fsSyncMutex.runExclusive(async () => { this.#fsSyncScheduled = false; - await this.fs!.syncToFs(this.mod!.FS); + await this.fs!.syncToFs(this.mod!.FS, this.#relaxedDurability); }); }; diff --git a/packages/pglite/tests/targets/base.js b/packages/pglite/tests/targets/base.js index ca0c80b5..7239c005 100644 --- a/packages/pglite/tests/targets/base.js +++ b/packages/pglite/tests/targets/base.js @@ -3,6 +3,8 @@ import playwright from "playwright"; const wsPort = process.env.WS_PORT || 3334; +const useWorkerForBbFilename = ["opfs-ahp://base"]; + export function tests(env, dbFilename, target) { let browser; let evaluate; @@ -30,6 +32,7 @@ export function tests(env, dbFilename, target) { page = await context.newPage(); await page.goto(`http://localhost:${wsPort}/tests/blank.html`); page.evaluate(`window.dbFilename = "${dbFilename}";`); + page.evaluate(`window.useWorkerForBbFilename = ${JSON.stringify(useWorkerForBbFilename)};`); page.on("console", (msg) => { console.log(msg); }); @@ -46,8 +49,20 @@ export function tests(env, dbFilename, target) { test.serial(`targets ${target} basic`, async (t) => { const res = await evaluate(async () => { - const { PGlite } = await import("../../dist/index.js"); - db = new PGlite(dbFilename); + if (useWorkerForBbFilename.includes(dbFilename)) { + const { PGliteWorker } = await import("../../dist/worker/index.js"); + db = new PGliteWorker( + new Worker("/tests/targets/worker.js", { + type: "module", + }), + { + dataDir: dbFilename, + } + ); + } else { + const { PGlite } = await import("../../dist/index.js"); + db = new PGlite(dbFilename); + } await db.waitReady; await db.query(` CREATE TABLE IF NOT EXISTS test ( @@ -125,10 +140,24 @@ export function tests(env, dbFilename, target) { test.serial(`targets ${target} persisted`, async (t) => { await page?.reload(); // Refresh the page page?.evaluate(`window.dbFilename = "${dbFilename}";`); + page?.evaluate(`window.useWorkerForBbFilename = ${JSON.stringify(useWorkerForBbFilename)};`); const res = await evaluate(async () => { - const { PGlite } = await import("../../dist/index.js"); - const db = new PGlite(dbFilename); + let db; + if (useWorkerForBbFilename.includes(dbFilename)) { + const { PGliteWorker } = await import("../../dist/worker/index.js"); + db = new PGliteWorker( + new Worker("/tests/targets/worker.js", { + type: "module", + }), + { + dataDir: dbFilename, + } + ); + } else { + const { PGlite } = await import("../../dist/index.js"); + db = new PGlite(dbFilename); + } await db.waitReady; const res = await db.query(` SELECT * FROM test; diff --git a/packages/pglite/tests/targets/chromium-opfs-ahp.test.js b/packages/pglite/tests/targets/chromium-opfs-ahp.test.js new file mode 100644 index 00000000..901b2ef2 --- /dev/null +++ b/packages/pglite/tests/targets/chromium-opfs-ahp.test.js @@ -0,0 +1,3 @@ +import { tests } from "./base.js"; + +tests("chromium", "opfs-ahp://base", "chromium.opfs-ahp"); diff --git a/packages/pglite/tests/targets/firefox-opfs-ahp.test.js b/packages/pglite/tests/targets/firefox-opfs-ahp.test.js new file mode 100644 index 00000000..0bb9cddc --- /dev/null +++ b/packages/pglite/tests/targets/firefox-opfs-ahp.test.js @@ -0,0 +1,3 @@ +import { tests } from "./base.js"; + +tests("firefox", "opfs-ahp://base", "firefox.opfs-ahp"); diff --git a/packages/pglite/tests/targets/webkit-opfs-ahp.test.js b/packages/pglite/tests/targets/webkit-opfs-ahp.test.js new file mode 100644 index 00000000..5f884dda --- /dev/null +++ b/packages/pglite/tests/targets/webkit-opfs-ahp.test.js @@ -0,0 +1,5 @@ +import { tests } from "./base.js"; + +// There is an issue with webkit opening more than 252 access handles, this +// prevents the opfs-ahp VFS working on webkit. :-( +// tests("webkit", "opfs-ahp://base", "webkit.opfs-ahp"); diff --git a/packages/pglite/tsup.config.ts b/packages/pglite/tsup.config.ts index 87781168..c0a184ab 100644 --- a/packages/pglite/tsup.config.ts +++ b/packages/pglite/tsup.config.ts @@ -20,6 +20,8 @@ const entryPoints = [ 'src/live/index.ts', "src/worker/index.ts", "src/vector/index.ts", + "src/fs/opfs-ahp/index.ts", + "src/fs/nodefs.ts", ]; export default defineConfig({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 812cec5a..efb0269c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,8 +16,8 @@ importers: packages/benchmark: dependencies: wa-sqlite: - specifier: github:rhashimoto/wa-sqlite - version: github.com/rhashimoto/wa-sqlite/f1ab3d5d795fb4156e0b8e20ce2f58c05dfee74a + specifier: github:rhashimoto/wa-sqlite#v0.9.14 + version: github.com/rhashimoto/wa-sqlite/6dbe4f044502a7a285e815896f56304a808fe25b devDependencies: '@types/better-sqlite3': specifier: ^7.6.9 @@ -73,12 +73,15 @@ importers: prettier: specifier: 3.2.5 version: 3.2.5 + serve: + specifier: ^14.2.3 + version: 14.2.3 tinytar: specifier: ^0.1.0 version: 0.1.0 tsup: - specifier: ^8.0.2 - version: 8.0.2(typescript@5.3.3) + specifier: ^8.1.0 + version: 8.2.3(tsx@4.7.1)(typescript@5.3.3) tsx: specifier: ^4.7.1 version: 4.7.1 @@ -576,6 +579,15 @@ packages: dev: true optional: true + /@esbuild/aix-ppc64@0.23.0: + resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.19.12: resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} @@ -594,6 +606,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.23.0: + resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.19.12: resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} @@ -612,6 +633,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.23.0: + resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.19.12: resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} @@ -630,6 +660,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.23.0: + resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.19.12: resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} @@ -648,6 +687,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.23.0: + resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.19.12: resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} @@ -666,6 +714,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.23.0: + resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.19.12: resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} @@ -684,6 +741,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.23.0: + resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.19.12: resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} @@ -702,6 +768,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.23.0: + resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.19.12: resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} @@ -720,6 +795,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.23.0: + resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.19.12: resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} @@ -738,6 +822,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.23.0: + resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.19.12: resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} @@ -756,6 +849,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.23.0: + resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.19.12: resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} @@ -774,6 +876,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.23.0: + resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.19.12: resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} @@ -792,6 +903,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.23.0: + resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.19.12: resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} @@ -810,6 +930,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.23.0: + resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.19.12: resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} @@ -828,6 +957,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.23.0: + resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.19.12: resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} @@ -846,6 +984,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.23.0: + resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.19.12: resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} @@ -864,6 +1011,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.23.0: + resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.19.12: resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} @@ -882,6 +1038,24 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.23.0: + resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.23.0: + resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.19.12: resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} @@ -900,6 +1074,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.23.0: + resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.19.12: resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} @@ -918,6 +1101,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.23.0: + resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.19.12: resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} @@ -936,6 +1128,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.23.0: + resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.19.12: resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} @@ -954,6 +1155,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.23.0: + resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.19.12: resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} @@ -972,6 +1182,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.23.0: + resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1043,15 +1262,6 @@ packages: wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 - dev: true - /@jridgewell/gen-mapping@0.3.5: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -1066,11 +1276,6 @@ packages: engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/set-array@1.2.1: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} @@ -1087,13 +1292,6 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: @@ -1293,80 +1491,80 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/rollup-android-arm-eabi@4.12.0: - resolution: {integrity: sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==} + /@rollup/rollup-android-arm-eabi@4.18.0: + resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm-eabi@4.18.0: - resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} + /@rollup/rollup-android-arm-eabi@4.19.1: + resolution: {integrity: sha512-XzqSg714++M+FXhHfXpS1tDnNZNpgxxuGZWlRG/jSj+VEPmZ0yg6jV4E0AL3uyBKxO8mO3xtOsP5mQ+XLfrlww==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.12.0: - resolution: {integrity: sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==} + /@rollup/rollup-android-arm64@4.18.0: + resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.18.0: - resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} + /@rollup/rollup-android-arm64@4.19.1: + resolution: {integrity: sha512-thFUbkHteM20BGShD6P08aungq4irbIZKUNbG70LN8RkO7YztcGPiKTTGZS7Kw+x5h8hOXs0i4OaHwFxlpQN6A==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.12.0: - resolution: {integrity: sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==} + /@rollup/rollup-darwin-arm64@4.18.0: + resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.18.0: - resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} + /@rollup/rollup-darwin-arm64@4.19.1: + resolution: {integrity: sha512-8o6eqeFZzVLia2hKPUZk4jdE3zW7LCcZr+MD18tXkgBBid3lssGVAYuox8x6YHoEPDdDa9ixTaStcmx88lio5Q==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.12.0: - resolution: {integrity: sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==} + /@rollup/rollup-darwin-x64@4.18.0: + resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.18.0: - resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} + /@rollup/rollup-darwin-x64@4.19.1: + resolution: {integrity: sha512-4T42heKsnbjkn7ovYiAdDVRRWZLU9Kmhdt6HafZxFcUdpjlBlxj4wDrt1yFWLk7G4+E+8p2C9tcmSu0KA6auGA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.12.0: - resolution: {integrity: sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==} + /@rollup/rollup-linux-arm-gnueabihf@4.18.0: + resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.18.0: - resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} + /@rollup/rollup-linux-arm-gnueabihf@4.19.1: + resolution: {integrity: sha512-MXg1xp+e5GhZ3Vit1gGEyoC+dyQUBy2JgVQ+3hUrD9wZMkUw/ywgkpK7oZgnB6kPpGrxJ41clkPPnsknuD6M2Q==} cpu: [arm] os: [linux] requiresBuild: true @@ -1381,9 +1579,9 @@ packages: dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.12.0: - resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==} - cpu: [arm64] + /@rollup/rollup-linux-arm-musleabihf@4.19.1: + resolution: {integrity: sha512-DZNLwIY4ftPSRVkJEaxYkq7u2zel7aah57HESuNkUnz+3bZHxwkCUkrfS2IWC1sxK6F2QNIR0Qr/YXw7nkF3Pw==} + cpu: [arm] os: [linux] requiresBuild: true dev: true @@ -1397,8 +1595,8 @@ packages: dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.12.0: - resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==} + /@rollup/rollup-linux-arm64-gnu@4.19.1: + resolution: {integrity: sha512-C7evongnjyxdngSDRRSQv5GvyfISizgtk9RM+z2biV5kY6S/NF/wta7K+DanmktC5DkuaJQgoKGf7KUDmA7RUw==} cpu: [arm64] os: [linux] requiresBuild: true @@ -1413,6 +1611,14 @@ packages: dev: true optional: true + /@rollup/rollup-linux-arm64-musl@4.19.1: + resolution: {integrity: sha512-89tFWqxfxLLHkAthAcrTs9etAoBFRduNfWdl2xUs/yLV+7XDrJ5yuXMHptNqf1Zw0UCA3cAutkAiAokYCkaPtw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@rollup/rollup-linux-powerpc64le-gnu@4.18.0: resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} cpu: [ppc64] @@ -1421,9 +1627,9 @@ packages: dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.12.0: - resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==} - cpu: [riscv64] + /@rollup/rollup-linux-powerpc64le-gnu@4.19.1: + resolution: {integrity: sha512-PromGeV50sq+YfaisG8W3fd+Cl6mnOOiNv2qKKqKCpiiEke2KiKVyDqG/Mb9GWKbYMHj5a01fq/qlUR28PFhCQ==} + cpu: [ppc64] os: [linux] requiresBuild: true dev: true @@ -1437,6 +1643,14 @@ packages: dev: true optional: true + /@rollup/rollup-linux-riscv64-gnu@4.19.1: + resolution: {integrity: sha512-/1BmHYh+iz0cNCP0oHCuF8CSiNj0JOGf0jRlSo3L/FAyZyG2rGBuKpkZVH9YF+x58r1jgWxvm1aRg3DHrLDt6A==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@rollup/rollup-linux-s390x-gnu@4.18.0: resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} cpu: [s390x] @@ -1445,9 +1659,9 @@ packages: dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.12.0: - resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==} - cpu: [x64] + /@rollup/rollup-linux-s390x-gnu@4.19.1: + resolution: {integrity: sha512-0cYP5rGkQWRZKy9/HtsWVStLXzCF3cCBTRI+qRL8Z+wkYlqN7zrSYm6FuY5Kd5ysS5aH0q5lVgb/WbG4jqXN1Q==} + cpu: [s390x] os: [linux] requiresBuild: true dev: true @@ -1461,8 +1675,8 @@ packages: dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.12.0: - resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==} + /@rollup/rollup-linux-x64-gnu@4.19.1: + resolution: {integrity: sha512-XUXeI9eM8rMP8aGvii/aOOiMvTs7xlCosq9xCjcqI9+5hBxtjDpD+7Abm1ZhVIFE1J2h2VIg0t2DX/gjespC2Q==} cpu: [x64] os: [linux] requiresBuild: true @@ -1477,10 +1691,10 @@ packages: dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.12.0: - resolution: {integrity: sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==} - cpu: [arm64] - os: [win32] + /@rollup/rollup-linux-x64-musl@4.19.1: + resolution: {integrity: sha512-V7cBw/cKXMfEVhpSvVZhC+iGifD6U1zJ4tbibjjN+Xi3blSXaj/rJynAkCFFQfoG6VZrAiP7uGVzL440Q6Me2Q==} + cpu: [x64] + os: [linux] requiresBuild: true dev: true optional: true @@ -1493,9 +1707,9 @@ packages: dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.12.0: - resolution: {integrity: sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==} - cpu: [ia32] + /@rollup/rollup-win32-arm64-msvc@4.19.1: + resolution: {integrity: sha512-88brja2vldW/76jWATlBqHEoGjJLRnP0WOEKAUbMcXaAZnemNhlAHSyj4jIwMoP2T750LE9lblvD4e2jXleZsA==} + cpu: [arm64] os: [win32] requiresBuild: true dev: true @@ -1509,9 +1723,9 @@ packages: dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.12.0: - resolution: {integrity: sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==} - cpu: [x64] + /@rollup/rollup-win32-ia32-msvc@4.19.1: + resolution: {integrity: sha512-LdxxcqRVSXi6k6JUrTah1rHuaupoeuiv38du8Mt4r4IPer3kwlTo+RuvfE8KzZ/tL6BhaPlzJ3835i6CxrFIRQ==} + cpu: [ia32] os: [win32] requiresBuild: true dev: true @@ -1525,6 +1739,14 @@ packages: dev: true optional: true + /@rollup/rollup-win32-x64-msvc@4.19.1: + resolution: {integrity: sha512-2bIrL28PcK3YCqD9anGxDxamxdiJAxA+l7fWIwM5o8UqNy1t3d1NdAweO2XhA0KTDJ5aH1FsuiT5+7VhtHliXg==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@rushstack/node-core-library@4.0.2: resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} peerDependencies: @@ -1951,10 +2173,22 @@ packages: resolution: {integrity: sha512-hQ2gAQcBO/CDpC82DCrinJNgOHI2v+FA7BDW4lMSPeBpQ7sRe2OLHWe5cph1s7D8DUQAwRt18dBDfJJ220APEA==} dev: true + /@zeit/schemas@2.36.0: + resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} + dev: true + /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: true + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: true + /acorn-import-attributes@1.9.2(acorn@8.11.3): resolution: {integrity: sha512-O+nfJwNolEA771IYJaiLWK1UAwjNsQmZbTRqqwBYxCgVQTmpFEMvBw6LOIQV0Me339L5UMVYFyRohGnGlQDdIQ==} peerDependencies: @@ -2000,6 +2234,21 @@ packages: uri-js: 4.4.1 dev: true + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: true + + /ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + dependencies: + string-width: 4.2.3 + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2045,6 +2294,10 @@ packages: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} dev: true + /arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + dev: true + /are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} @@ -2053,6 +2306,10 @@ packages: readable-stream: 3.6.2 dev: true + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -2216,6 +2473,20 @@ packages: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: true + /boxen@7.0.0: + resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} + engines: {node: '>=14.16'} + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.1 + chalk: 5.3.0 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.19.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -2287,16 +2558,21 @@ packages: '@oven/bun-windows-x64-baseline': 1.1.18 dev: true - /bundle-require@4.0.2(esbuild@0.19.12): - resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + /bundle-require@5.0.0(esbuild@0.23.0): + resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: - esbuild: '>=0.17' + esbuild: '>=0.18' dependencies: - esbuild: 0.19.12 + esbuild: 0.23.0 load-tsconfig: 0.2.5 dev: true + /bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + dev: true + /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -2323,6 +2599,11 @@ packages: engines: {node: '>=12.20'} dev: true + /camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + dev: true + /caniuse-lite@1.0.30001636: resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} dev: true @@ -2334,6 +2615,13 @@ packages: nofilter: 3.1.0 dev: true + /chalk-template@0.4.0: + resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} + engines: {node: '>=12'} + dependencies: + chalk: 4.1.2 + dev: true + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2351,6 +2639,11 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.0.1: + resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + /chalk@5.3.0: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -2393,6 +2686,11 @@ packages: resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} dev: true + /cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + dev: true + /cli-truncate@4.0.0: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} engines: {node: '>=18'} @@ -2401,6 +2699,15 @@ packages: string-width: 7.1.0 dev: true + /clipboardy@3.0.0: + resolution: {integrity: sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + arch: 2.2.0 + execa: 5.1.1 + is-wsl: 2.2.0 + dev: true + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2484,6 +2791,28 @@ packages: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} dev: true + /compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: true + /computeds@0.0.1: resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} dev: true @@ -2522,10 +2851,20 @@ packages: yargs: 17.7.2 dev: true + /consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + dev: true + /console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: true + /content-disposition@0.5.2: + resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} + engines: {node: '>= 0.6'} + dev: true + /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true @@ -2582,6 +2921,17 @@ packages: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} dev: true + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: true + /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -2605,6 +2955,18 @@ packages: ms: 2.1.2 dev: true + /debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + /decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -2786,6 +3148,38 @@ packages: '@esbuild/win32-x64': 0.21.5 dev: true + /esbuild@0.23.0: + resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.0 + '@esbuild/android-arm': 0.23.0 + '@esbuild/android-arm64': 0.23.0 + '@esbuild/android-x64': 0.23.0 + '@esbuild/darwin-arm64': 0.23.0 + '@esbuild/darwin-x64': 0.23.0 + '@esbuild/freebsd-arm64': 0.23.0 + '@esbuild/freebsd-x64': 0.23.0 + '@esbuild/linux-arm': 0.23.0 + '@esbuild/linux-arm64': 0.23.0 + '@esbuild/linux-ia32': 0.23.0 + '@esbuild/linux-loong64': 0.23.0 + '@esbuild/linux-mips64el': 0.23.0 + '@esbuild/linux-ppc64': 0.23.0 + '@esbuild/linux-riscv64': 0.23.0 + '@esbuild/linux-s390x': 0.23.0 + '@esbuild/linux-x64': 0.23.0 + '@esbuild/netbsd-x64': 0.23.0 + '@esbuild/openbsd-arm64': 0.23.0 + '@esbuild/openbsd-x64': 0.23.0 + '@esbuild/sunos-x64': 0.23.0 + '@esbuild/win32-arm64': 0.23.0 + '@esbuild/win32-ia32': 0.23.0 + '@esbuild/win32-x64': 0.23.0 + dev: true + /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -2982,6 +3376,12 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-url-parser@1.1.3: + resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} + dependencies: + punycode: 1.4.1 + dev: true + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: @@ -3187,7 +3587,7 @@ packages: dependencies: foreground-child: 3.1.1 jackspeak: 2.3.6 - minimatch: 9.0.3 + minimatch: 9.0.4 minipass: 7.0.4 path-scurry: 1.10.1 dev: true @@ -3428,6 +3828,12 @@ packages: hasown: 2.0.1 dev: true + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -3465,6 +3871,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-port-reachable@4.0.0: + resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} dev: true @@ -3479,6 +3890,13 @@ packages: engines: {node: '>=18'} dev: true + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true @@ -3538,6 +3956,10 @@ packages: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true @@ -3694,11 +4116,23 @@ packages: picomatch: 2.3.1 dev: true + /mime-db@1.33.0: + resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} + engines: {node: '>= 0.6'} + dev: true + /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} dev: true + /mime-types@2.1.18: + resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.33.0 + dev: true + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -3799,6 +4233,10 @@ packages: hasBin: true dev: true + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: true + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true @@ -3833,6 +4271,11 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: true + /node-abi@3.56.0: resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==} engines: {node: '>=10'} @@ -3904,6 +4347,11 @@ packages: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} dev: true + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + dev: true + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -3991,6 +4439,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /path-is-inside@1.0.2: + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} + dev: true + /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -4008,6 +4460,10 @@ packages: minipass: 7.0.4 dev: true + /path-to-regexp@2.2.1: + resolution: {integrity: sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==} + dev: true + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -4140,20 +4596,26 @@ packages: - supports-color dev: true - /postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} + /postcss-load-config@6.0.1(tsx@4.7.1): + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: + jiti: '>=1.21.0' postcss: '>=8.0.9' - ts-node: '>=9.0.0' + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: + jiti: + optional: true postcss: optional: true - ts-node: + tsx: + optional: true + yaml: optional: true dependencies: lilconfig: 3.1.1 - yaml: 2.3.4 + tsx: 4.7.1 dev: true /postcss@8.4.38: @@ -4239,6 +4701,10 @@ packages: once: 1.4.0 dev: true + /punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + dev: true + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4255,6 +4721,11 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /range-parser@1.2.0: + resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} + engines: {node: '>= 0.6'} + dev: true + /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -4306,11 +4777,30 @@ packages: /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + /registry-auth-token@3.3.2: + resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} + dependencies: + rc: 1.2.8 + safe-buffer: 5.2.1 + dev: true + + /registry-url@3.1.0: + resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} + engines: {node: '>=0.10.0'} + dependencies: + rc: 1.2.8 + dev: true + /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} dev: true + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: true @@ -4364,29 +4854,6 @@ packages: glob: 7.2.3 dev: true - /rollup@4.12.0: - resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.12.0 - '@rollup/rollup-android-arm64': 4.12.0 - '@rollup/rollup-darwin-arm64': 4.12.0 - '@rollup/rollup-darwin-x64': 4.12.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.12.0 - '@rollup/rollup-linux-arm64-gnu': 4.12.0 - '@rollup/rollup-linux-arm64-musl': 4.12.0 - '@rollup/rollup-linux-riscv64-gnu': 4.12.0 - '@rollup/rollup-linux-x64-gnu': 4.12.0 - '@rollup/rollup-linux-x64-musl': 4.12.0 - '@rollup/rollup-win32-arm64-msvc': 4.12.0 - '@rollup/rollup-win32-ia32-msvc': 4.12.0 - '@rollup/rollup-win32-x64-msvc': 4.12.0 - fsevents: 2.3.3 - dev: true - /rollup@4.18.0: resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4413,6 +4880,32 @@ packages: fsevents: 2.3.3 dev: true + /rollup@4.19.1: + resolution: {integrity: sha512-K5vziVlg7hTpYfFBI+91zHBEMo6jafYXpkMlqZjg7/zhIG9iHqazBf4xz9AVdjS9BruRn280ROqLI7G3OFRIlw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.19.1 + '@rollup/rollup-android-arm64': 4.19.1 + '@rollup/rollup-darwin-arm64': 4.19.1 + '@rollup/rollup-darwin-x64': 4.19.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.19.1 + '@rollup/rollup-linux-arm-musleabihf': 4.19.1 + '@rollup/rollup-linux-arm64-gnu': 4.19.1 + '@rollup/rollup-linux-arm64-musl': 4.19.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.19.1 + '@rollup/rollup-linux-riscv64-gnu': 4.19.1 + '@rollup/rollup-linux-s390x-gnu': 4.19.1 + '@rollup/rollup-linux-x64-gnu': 4.19.1 + '@rollup/rollup-linux-x64-musl': 4.19.1 + '@rollup/rollup-win32-arm64-msvc': 4.19.1 + '@rollup/rollup-win32-ia32-msvc': 4.19.1 + '@rollup/rollup-win32-x64-msvc': 4.19.1 + fsevents: 2.3.3 + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -4475,6 +4968,39 @@ packages: type-fest: 0.13.1 dev: true + /serve-handler@6.1.5: + resolution: {integrity: sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==} + dependencies: + bytes: 3.0.0 + content-disposition: 0.5.2 + fast-url-parser: 1.1.3 + mime-types: 2.1.18 + minimatch: 3.1.2 + path-is-inside: 1.0.2 + path-to-regexp: 2.2.1 + range-parser: 1.2.0 + dev: true + + /serve@14.2.3: + resolution: {integrity: sha512-VqUFMC7K3LDGeGnJM9h56D3XGKb6KGgOw0cVNtA26yYXHCcpxf3xwCTUaQoWlVS7i8Jdh3GjQkOB23qsXyjoyQ==} + engines: {node: '>= 14'} + hasBin: true + dependencies: + '@zeit/schemas': 2.36.0 + ajv: 8.12.0 + arg: 5.0.2 + boxen: 7.0.0 + chalk: 5.0.1 + chalk-template: 0.4.0 + clipboardy: 3.0.0 + compression: 1.7.4 + is-port-reachable: 4.0.0 + serve-handler: 6.1.5 + update-check: 1.5.4 + transitivePeerDependencies: + - supports-color + dev: true + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true @@ -4676,7 +5202,7 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true dependencies: - '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 glob: 10.3.10 lines-and-columns: 1.2.4 @@ -4840,8 +5366,8 @@ packages: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true - /tsup@8.0.2(typescript@5.3.3): - resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} + /tsup@8.2.3(tsx@4.7.1)(typescript@5.3.3): + resolution: {integrity: sha512-6YNT44oUfXRbZuSMNmN36GzwPPIlD2wBccY7looM2fkTcxkf2NEmwr3OZuDZoySklnrIG4hoEtzy8yUXYOqNcg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -4859,24 +5385,28 @@ packages: typescript: optional: true dependencies: - bundle-require: 4.0.2(esbuild@0.19.12) + bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 chokidar: 3.6.0 - debug: 4.3.4 - esbuild: 0.19.12 + consola: 3.2.3 + debug: 4.3.6 + esbuild: 0.23.0 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.2 + picocolors: 1.0.1 + postcss-load-config: 6.0.1(tsx@4.7.1) resolve-from: 5.0.0 - rollup: 4.12.0 + rollup: 4.19.1 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tree-kill: 1.2.2 typescript: 5.3.3 transitivePeerDependencies: + - jiti - supports-color - - ts-node + - tsx + - yaml dev: true /tsx@4.7.1: @@ -4913,6 +5443,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + /typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} @@ -4957,6 +5492,13 @@ packages: picocolors: 1.0.1 dev: true + /update-check@1.5.4: + resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} + dependencies: + registry-auth-token: 3.3.2 + registry-url: 3.1.0 + dev: true + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -4976,6 +5518,11 @@ packages: engines: {node: '>= 0.10'} dev: true + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: true + /vite-plugin-dts@3.9.1(typescript@5.3.3)(vite@5.3.1): resolution: {integrity: sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -5118,6 +5665,13 @@ packages: string-width: 4.2.3 dev: true + /widest-line@4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + dev: true + /word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -5171,11 +5725,6 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yaml@2.3.4: - resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} - engines: {node: '>= 14'} - dev: true - /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -5211,8 +5760,8 @@ packages: commander: 9.5.0 dev: true - github.com/rhashimoto/wa-sqlite/f1ab3d5d795fb4156e0b8e20ce2f58c05dfee74a: - resolution: {tarball: https://codeload.github.com/rhashimoto/wa-sqlite/tar.gz/f1ab3d5d795fb4156e0b8e20ce2f58c05dfee74a} + github.com/rhashimoto/wa-sqlite/6dbe4f044502a7a285e815896f56304a808fe25b: + resolution: {tarball: https://codeload.github.com/rhashimoto/wa-sqlite/tar.gz/6dbe4f044502a7a285e815896f56304a808fe25b} name: wa-sqlite - version: 1.0.0 + version: 0.9.14 dev: false