diff --git a/.eslintrc.cjs b/.eslintrc.cjs
deleted file mode 100644
index c1bd204..0000000
--- a/.eslintrc.cjs
+++ /dev/null
@@ -1,30 +0,0 @@
-module.exports = {
- "env": {
- "es6": true,
- "node": true,
- "mocha": true
- },
- "parserOptions": {
- "ecmaVersion": 2017,
- "sourceType": "module"
- },
- "extends": "eslint:recommended",
- "rules": {
- "indent": [
- "error",
- 4
- ],
- "linebreak-style": [
- "warn",
- "unix"
- ],
- "quotes": [
- "error",
- "double"
- ],
- "semi": [
- "error",
- "always"
- ]
- }
-};
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6df4591
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,11 @@
+# Normalize all text to LF in the repository and in every checkout,
+# regardless of the local core.autocrlf setting.
+* text=auto eol=lf
+
+# Binary test fixtures and artifacts: never subject to EOL conversion.
+*.zkey -text
+*.ptau -text
+*.wtns -text
+*.r1cs -text
+*.wasm -text
+*.png -text
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d0706d5..6f3d14e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,12 +2,13 @@ name: Continuous Integration
on:
push:
branches:
- - main
+ - master
pull_request:
jobs:
test:
name: Test
+ timeout-minutes: 15
runs-on: ${{ matrix.os }}
strategy:
@@ -18,10 +19,10 @@ jobs:
steps:
- name: Checkout project
- uses: actions/checkout@v3
+ uses: actions/checkout@v6
- name: Setup Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
check-latest: true
@@ -30,5 +31,8 @@ jobs:
- name: Install dependencies
run: npm ci
+ - name: Install Playwright dependencies
+ run: npx playwright install
+
- name: Run tests
run: npm test
diff --git a/.gitignore b/.gitignore
index 9e7d574..03111aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,3 +67,7 @@ tmp
# Workspace files are user-specific
*.sublime-workspace
+
+# vitest browser-mode artifacts (failure screenshots, attachments)
+.vitest-attachments/
+test/__screenshots__/
diff --git a/README.md b/README.md
index 4efaf3d..e1b2e3d 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,176 @@
# fastfile
-fastfile is a package to read/write binary files with a transparent cache.
+fastfile is a package to read/write binary files through one small async API
+backed by a transparent page cache. The same `FastFile` interface works over
+several backends, so code written against it (for example the snarkjs
+zkey/ptau readers) runs unchanged whether the data lives on disk, in memory,
+behind an HTTP URL, or inside a browser `Blob`.
+
+## Capabilities
+
+- **Page-cached reads and writes** — small reads (headers, section tables,
+ `readULE32`-style scans) are served from cached pages; writes are cached and
+ flushed asynchronously, so sequential access to big files stays fast.
+- **Multiple backends behind one API**:
+
+ | Backend | Type tag | Where | What it is for |
+ |---|---|---|---|
+ | OS file | `file` | Node | Regular files, with direct-I/O fast paths for large aligned reads/writes |
+ | Memory | `mem` | Node + browser | A `Uint8Array` you already have, or a scratch file that never touches disk |
+ | Big memory | `bigMem` | Node + browser | Like `mem`, but paged so it can hold buffers past the V8 single-allocation limits |
+ | HTTP(S) | `http` | Node + browser | Read-only streaming over `Range` requests; falls back to buffering the whole body when the server does not support ranges |
+ | Blob | `blob` | Browser (and Node ≥ 18) | Read-only zero-copy reads from a `Blob`/`File` (e.g. ``), so multi-GB files stream chunk-by-chunk |
+
+- **Bounded memory on huge remote files** — with the `http` and `blob`
+ backends, large reads stream straight into the caller's buffer and only the
+ small-read page cache is retained; the whole file is never resident.
+- **Node/browser split at package level** — the `exports` map gives Node the
+ filesystem implementation and gives bundlers a browser build with the
+ file backend removed (`mem`, `bigMem`, `http` and `blob` remain).
+
+## Install
-This library maintains a read and write cache that allows to write asynchronously
-improving the speed of the reads and writes of big files.
+```
+npm install fastfile
+```
+
+## API
+
+All entry points return a promise of a `FastFile` handle:
-## Usage
+- `createOverride(o, cacheSize?, pageSize?)` — create a file, truncating any
+ existing one.
+- `createNoOverride(o, cacheSize?, pageSize?)` — create a file, failing if it
+ already exists (Node only distinction; alias of `createOverride` in the
+ browser).
+- `readExisting(o, cacheSize?, pageSize?)` — open read-only. Accepts the most
+ input shapes (see the examples).
+- `readWriteExisting(o, cacheSize?, pageSize?)` — open an existing file
+ read/write.
+- `readWriteExistingOrCreate(o, cacheSize?, pageSize?)` — like the above but
+ creates the file when missing.
+
+`o` is a file name/URL string, a `Uint8Array`, a `Blob`, or an options object
+with a `type` tag from the table above. `cacheSize` (default 64 KiB) and
+`pageSize` (default 8 KiB) tune the page cache. They apply to every source
+form: for an options object they fill only the fields the object leaves
+undefined, so explicit fields on the object always win.
+
+The returned handle offers, among others:
```
-npm install fastfile
+read(len, pos) readToBuffer(buff, offset, len, pos)
+write(buff, pos) readString(pos)
+readULE32/readULE64/readUBE32(pos)
+writeULE32/writeULE64/writeUBE32(v, pos)
+totalSize close() discard()
```
-```javascript
+Reads return `Uint8Array`s. `close()` flushes pending writes and is
+idempotent (repeat calls return the same promise instead of throwing).
-const fastFile = require("fastfile");
+## Examples
-async function writeFile() {
- const f = await fastFile.createOverride("pattern.bin");
+### OS files (Node)
- const buff = Buffer.from("0001020304050607", "hex");
- for (let i=0; i<1000; i++) {
- await f.write(buff, i*8);
- }
+```javascript
+import * as fastFile from "fastfile";
- await f.close();
+const f = await fastFile.createOverride("pattern.bin");
+const buff = Buffer.from("0001020304050607", "hex");
+for (let i = 0; i < 1000; i++) {
+ await f.write(buff, i * 8);
}
+await f.close();
-async function readFile() {
- const f = await fastFile.readExisting("pattern.bin");
+const r = await fastFile.readExisting("pattern.bin");
+const bytes = await r.read(16, 8); // 16 bytes from offset 8
+await r.close();
+```
- const buff = await f.read(16, 8);
+From CommonJS use `const fastFile = require("fastfile");` — the `require`
+condition resolves to the CJS build.
- await f.close();
+### Memory
- return buff;
+```javascript
+// Wrap bytes you already have (zero-copy):
+const f1 = await fastFile.readExisting(new Uint8Array([1, 2, 3, 4]));
-}
+// Scratch file that never touches disk:
+const f2 = await fastFile.createOverride({ type: "mem" });
+await f2.writeULE32(42, 0);
+
+// Beyond the single-allocation limit (paged):
+const f3 = await fastFile.createOverride({ type: "bigMem" });
+```
-writeFile().then( () => {
- readFile().then( (buff) => {
- console.log(buff.toString("hex"));
- });
+### HTTP(S) with Range streaming
+
+```javascript
+// Works in Node and in the browser. Probes the server with
+// `Range: bytes=0-0`: when ranges are supported, every read becomes a range
+// request and large reads stream directly into your buffer -- the file is
+// never fully resident. When the server ignores Range, the body is buffered
+// once (the historical behavior).
+const f = await fastFile.readExisting("https://example.com/circuit_final.zkey");
+console.log(f.totalSize);
+const header = await f.read(32, 0);
+await f.close();
+
+// Explicit form with cache tuning:
+const g = await fastFile.readExisting({
+ type: "http",
+ url: "https://example.com/powersOfTau28_hez_final_10.ptau",
+ cacheSize: 1 << 20,
+ pageSize: 1 << 16,
});
+```
+
+#### Persistent warm start (browsers, experimental)
+```javascript
+// Opt-in: fetched blocks persist in IndexedDB, so a later session against
+// the same URL serves its reads locally instead of re-downloading.
+const f = await fastFile.readExisting({
+ type: "http",
+ url: "https://example.com/circuit_final.zkey",
+ cache: true, // or tune it:
+ // cache: { blockSize: 1 << 21, maxBytes: 1 << 29, dbName: "fastfile-http-cache" },
+});
```
-## License
+Entries are keyed by URL plus the server's strong validator (ETag /
+Last-Modified) and are dropped when the remote file changes; without a
+strong validator nothing is cached. Works for Range-less servers too: the
+first session persists the fully-downloaded body, and later sessions probe
+conditionally (If-None-Match / If-Modified-Since) -- an unchanged file
+answers a bodyless 304 and every read is served locally. Total storage is bounded (`maxBytes`,
+default 512 MiB) with least-recently-opened files evicted first. Where
+IndexedDB is unavailable (Node, private windows, blocked storage) the option
+is a silent no-op and reads stream as usual.
+
+### Blob / File (browser)
-fastfile is part of the iden3 project copyright 2018 0KIMS association and published with GPL-3 license. Please check the COPYING file for more details.
+```javascript
+// e.g. a multi-GB zkey selected by the user; blob.slice() is zero-copy, so
+// bytes reach memory only as they are read.
+document.querySelector("input[type=file]").addEventListener("change", async (e) => {
+ const f = await fastFile.readExisting(e.target.files[0]);
+ const magic = await f.read(4, 0);
+ await f.close();
+});
+```
+
+### In the browser
+
+Bundlers pick the browser build automatically via the package `exports`.
+String inputs to `readExisting` are treated as URLs (there is no filesystem);
+writable files must be `mem`/`bigMem`. The file backend throws
+`"File I/O is not supported in the browser"`.
+
+## License
+fastfile is part of the iden3 project copyright 2018-2026 0KIMS association
+and published with GPL-3 license. Please check the COPYING file for more
+details.
diff --git a/build/browser/browser.esm.js b/build/browser/browser.esm.js
new file mode 100644
index 0000000..93fcf17
--- /dev/null
+++ b/build/browser/browser.esm.js
@@ -0,0 +1,674 @@
+//#region src/memfile.js
+function e(e) {
+ let t = e.initialSize || 1 << 20, n = new s();
+ return n.o = e, n.o.data = new Uint8Array(t), n.allocSize = t, n.totalSize = 0, n.readOnly = !1, n.pos = 0, n;
+}
+function t(e) {
+ let t = new s();
+ return t.o = e, t.allocSize = e.data.byteLength, t.totalSize = e.data.byteLength, t.readOnly = !0, t.pos = 0, t;
+}
+function n(e) {
+ let t = new s();
+ return t.o = e, t.allocSize = e.data.byteLength, t.totalSize = e.data.byteLength, t.readOnly = !1, t.pos = 0, t;
+}
+var r = /* @__PURE__ */ new Uint8Array(4), i = new DataView(r.buffer), a = /* @__PURE__ */ new Uint8Array(8), o = new DataView(a.buffer), s = class {
+ constructor() {
+ this.pageSize = 16384;
+ }
+ _resizeIfNeeded(e) {
+ if (e > this.allocSize) {
+ let t = Math.max(this.allocSize + (1 << 20), Math.floor(this.allocSize * 1.1), e), n = new Uint8Array(t);
+ n.set(this.o.data), this.o.data = n, this.allocSize = t;
+ }
+ }
+ async write(e, t) {
+ let n = this;
+ if (t === void 0 && (t = n.pos), this.readOnly) throw Error("Writing a read only file");
+ this._resizeIfNeeded(t + e.byteLength), this.o.data.set(e.slice(), t), t + e.byteLength > this.totalSize && (this.totalSize = t + e.byteLength), this.pos = t + e.byteLength;
+ }
+ async readToBuffer(e, t, n, r) {
+ let i = this;
+ if (r === void 0 && (r = i.pos), this.readOnly && r + n > this.totalSize) throw Error("Reading out of bounds");
+ this._resizeIfNeeded(r + n);
+ let a = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + r, n);
+ e.set(a, t), this.pos = r + n;
+ }
+ async read(e, t) {
+ let n = this, r = new Uint8Array(e);
+ return await n.readToBuffer(r, 0, e, t), r;
+ }
+ close() {
+ this.o.data.byteLength != this.totalSize && (this.o.data = this.o.data.slice(0, this.totalSize));
+ }
+ async discard() {}
+ async writeULE32(e, t) {
+ let n = this;
+ i.setUint32(0, e, !0), await n.write(r, t);
+ }
+ async writeUBE32(e, t) {
+ let n = this;
+ i.setUint32(0, e, !1), await n.write(r, t);
+ }
+ async writeULE64(e, t) {
+ let n = this;
+ o.setUint32(0, e & 4294967295, !0), o.setUint32(4, Math.floor(e / 4294967296), !0), await n.write(a, t);
+ }
+ async readULE32(e) {
+ let t = await this.read(4, e);
+ return new Uint32Array(t.buffer)[0];
+ }
+ async readUBE32(e) {
+ let t = await this.read(4, e);
+ return new DataView(t.buffer).getUint32(0, !1);
+ }
+ async readULE64(e) {
+ let t = await this.read(8, e), n = new Uint32Array(t.buffer);
+ return n[1] * 4294967296 + n[0];
+ }
+ async readString(e) {
+ let t = this, n = e === void 0 ? t.pos : e;
+ if (n >= this.totalSize) {
+ if (this.readOnly) throw Error("Reading out of bounds");
+ return "";
+ }
+ let r = new Uint8Array(t.o.data.buffer, n, this.totalSize - n), i = r.findIndex((e) => e === 0), a = i !== -1, o = "";
+ return a ? (o = new TextDecoder().decode(r.slice(0, i)), t.pos = n + i + 1) : t.pos = n, o;
+ }
+}, c = 1 << 22;
+function l(e) {
+ let t = e.initialSize || 0, n = new g();
+ n.o = e;
+ let r = t ? Math.floor((t - 1) / c) + 1 : 0;
+ n.o.data = [];
+ for (let e = 0; e < r - 1; e++) n.o.data.push(new Uint8Array(c));
+ return r && n.o.data.push(new Uint8Array(t - c * (r - 1))), n.totalSize = 0, n.readOnly = !1, n.pos = 0, n;
+}
+function u(e) {
+ let t = new g();
+ return t.o = e, t.totalSize = (e.data.length - 1) * c + e.data[e.data.length - 1].byteLength, t.readOnly = !0, t.pos = 0, t;
+}
+function d(e) {
+ let t = new g();
+ return t.o = e, t.totalSize = (e.data.length - 1) * c + e.data[e.data.length - 1].byteLength, t.readOnly = !1, t.pos = 0, t;
+}
+var f = /* @__PURE__ */ new Uint8Array(4), p = new DataView(f.buffer), m = /* @__PURE__ */ new Uint8Array(8), h = new DataView(m.buffer), g = class {
+ constructor() {
+ this.pageSize = 16384;
+ }
+ _resizeIfNeeded(e) {
+ if (e <= this.totalSize) return;
+ if (this.readOnly) throw Error("Reading out of file bounds");
+ let t = Math.floor((e - 1) / c) + 1;
+ for (let n = Math.max(this.o.data.length - 1, 0); n < t; n++) {
+ let r = n < t - 1 ? c : e - (t - 1) * c, i = new Uint8Array(r);
+ n == this.o.data.length - 1 && i.set(this.o.data[n]), this.o.data[n] = i;
+ }
+ this.totalSize = e;
+ }
+ async write(e, t) {
+ let n = this;
+ if (t === void 0 && (t = n.pos), this.readOnly) throw Error("Writing a read only file");
+ this._resizeIfNeeded(t + e.byteLength);
+ let r = Math.floor(t / c), i = t % c, a = e.byteLength;
+ for (; a > 0;) {
+ let t = i + a > c ? c - i : a, o = e.slice(e.byteLength - a, e.byteLength - a + t);
+ new Uint8Array(n.o.data[r].buffer, i, t).set(o), a -= t, r++, i = 0;
+ }
+ this.pos = t + e.byteLength;
+ }
+ async readToBuffer(e, t, n, r) {
+ let i = this;
+ if (r === void 0 && (r = i.pos), this.readOnly && r + n > this.totalSize) throw Error("Reading out of bounds");
+ this._resizeIfNeeded(r + n);
+ let a = Math.floor(r / c), o = r % c, s = n;
+ for (; s > 0;) {
+ let r = o + s > c ? c - o : s, l = new Uint8Array(i.o.data[a].buffer, o, r);
+ e.set(l, t + n - s), s -= r, a++, o = 0;
+ }
+ this.pos = r + n;
+ }
+ async read(e, t) {
+ let n = this, r = new Uint8Array(e);
+ return await n.readToBuffer(r, 0, e, t), r;
+ }
+ close() {}
+ async discard() {}
+ async writeULE32(e, t) {
+ let n = this;
+ p.setUint32(0, e, !0), await n.write(f, t);
+ }
+ async writeUBE32(e, t) {
+ let n = this;
+ p.setUint32(0, e, !1), await n.write(f, t);
+ }
+ async writeULE64(e, t) {
+ let n = this;
+ h.setUint32(0, e & 4294967295, !0), h.setUint32(4, Math.floor(e / 4294967296), !0), await n.write(m, t);
+ }
+ async readULE32(e) {
+ let t = await this.read(4, e);
+ return new Uint32Array(t.buffer)[0];
+ }
+ async readUBE32(e) {
+ let t = await this.read(4, e);
+ return new DataView(t.buffer).getUint32(0, !1);
+ }
+ async readULE64(e) {
+ let t = await this.read(8, e), n = new Uint32Array(t.buffer);
+ return n[1] * 4294967296 + n[0];
+ }
+ async readString(e) {
+ let t = this, n = e === void 0 ? t.pos : e;
+ if (n > this.totalSize) {
+ if (this.readOnly) throw Error("Reading out of bounds");
+ this._resizeIfNeeded(e);
+ }
+ let r = !1, i = "";
+ for (; !r;) {
+ let e = Math.floor(n / c), a = n % c;
+ if (t.o.data[e] === void 0) throw Error("ERROR");
+ let o = Math.min(2048, t.o.data[e].length - a);
+ if (o <= 0) return t.pos = n, i;
+ let s = new Uint8Array(t.o.data[e].buffer, a, o), l = s.findIndex((e) => e === 0);
+ r = l !== -1, r ? (i += new TextDecoder().decode(s.slice(0, l)), t.pos = e * c + a + l + 1) : (i += new TextDecoder().decode(s), t.pos = e * c + a + s.length), n = t.pos;
+ }
+ return i;
+ }
+}, _ = 1 << 20, v = 8192, y = class {
+ constructor(e, t, n, r) {
+ this.readRangeInto = e, this.totalSize = t, this.pos = 0, this.pageSize = r || v, this.maxPagesLoaded = Math.floor((n || _) / this.pageSize) + 1, this.pages = /* @__PURE__ */ new Map(), this.readOnly = !0;
+ }
+ _pageLen(e) {
+ let t = e * this.pageSize;
+ return Math.min(t + this.pageSize, this.totalSize) - t;
+ }
+ _loadPage(e) {
+ let t = this, n = t.pages.get(e);
+ if (n) return t.pages.delete(e), t.pages.set(e, n), n.promise;
+ let r = new Uint8Array(t._pageLen(e));
+ return n = {
+ buff: null,
+ promise: null
+ }, n.promise = t.readRangeInto(r, 0, e * t.pageSize, r.byteLength).then(function() {
+ return n.buff = r, r;
+ }, function(n) {
+ throw t.pages.delete(e), n;
+ }), t.pages.set(e, n), t._trimCache(), n.promise;
+ }
+ _trimCache() {
+ let e = this;
+ if (!(e.pages.size <= e.maxPagesLoaded)) for (let t of e.pages) {
+ if (e.pages.size <= e.maxPagesLoaded) return;
+ t[1].buff && e.pages.delete(t[0]);
+ }
+ }
+ async readToBuffer(e, t, n, r) {
+ let i = this;
+ if (n === 0) return;
+ if (i.pendingClose) throw Error("Reading a closing file");
+ if (r === void 0 && (r = i.pos), r + n > i.totalSize) throw Error("Reading out of bounds");
+ if (i.pos = r + n, n >= i.pageSize) {
+ await i.readRangeInto(e, t, r, n);
+ return;
+ }
+ let a = Math.floor(r / i.pageSize), o = Math.floor((r + n - 1) / i.pageSize), s = r % i.pageSize, c = 0;
+ for (let r = a; r <= o; r++) {
+ let a = await i._loadPage(r), o = Math.min(n - c, i.pageSize - s);
+ e.set(a.subarray(s, s + o), t + c), c += o, s = 0;
+ }
+ }
+ async read(e, t) {
+ let n = new Uint8Array(e);
+ return await this.readToBuffer(n, 0, e, t), n;
+ }
+ async readULE32(e) {
+ let t = await this.read(4, e);
+ return new Uint32Array(t.buffer)[0];
+ }
+ async readUBE32(e) {
+ let t = await this.read(4, e);
+ return new DataView(t.buffer).getUint32(0, !1);
+ }
+ async readULE64(e) {
+ let t = await this.read(8, e), n = new Uint32Array(t.buffer);
+ return n[1] * 4294967296 + n[0];
+ }
+ async readString(e) {
+ let t = this;
+ if (t.pendingClose) throw Error("Reading a closing file");
+ let n = e === void 0 ? t.pos : e, r = [];
+ for (; n < t.totalSize;) {
+ let e = Math.min(t.pageSize, t.totalSize - n), i = await t.read(e, n), a = i.indexOf(0);
+ if (a >= 0) return r.push(i.subarray(0, a)), t.pos = n + a + 1, b(r);
+ r.push(i), n += e;
+ }
+ return t.pos = n, b(r);
+ }
+ async write() {
+ throw Error("Writing a read only file");
+ }
+ async writeULE32() {
+ throw Error("Writing a read only file");
+ }
+ async writeUBE32() {
+ throw Error("Writing a read only file");
+ }
+ async writeULE64() {
+ throw Error("Writing a read only file");
+ }
+ async close() {
+ this.pendingClose || (this.pendingClose = !0, this.pages.clear());
+ }
+ async discard() {
+ await this.close();
+ }
+};
+function b(e) {
+ let t = 0;
+ for (let n = 0; n < e.length; n++) t += e[n].byteLength;
+ let n = new Uint8Array(t), r = 0;
+ for (let t = 0; t < e.length; t++) n.set(e[t], r), r += e[t].byteLength;
+ return new TextDecoder().decode(n);
+}
+//#endregion
+//#region src/idbcache.js
+var x = 1 << 21, S = 1 << 29, C = "fastfile-http-cache", w = /* @__PURE__ */ new Map();
+function T(e) {
+ if (w.has(e)) return w.get(e);
+ let t = new Promise((t, n) => {
+ let r = indexedDB.open(e, 1);
+ r.onupgradeneeded = () => {
+ let e = r.result;
+ e.createObjectStore("files"), e.createObjectStore("blocks");
+ }, r.onsuccess = () => t(r.result), r.onerror = () => n(r.error), r.onblocked = () => n(/* @__PURE__ */ Error("IndexedDB open blocked"));
+ });
+ return w.set(e, t), t.catch(() => w.delete(e)), t;
+}
+function E(e) {
+ return new Promise((t, n) => {
+ e.onsuccess = () => t(e.result), e.onerror = () => n(e.error);
+ });
+}
+function D(e) {
+ return new Promise((t, n) => {
+ e.oncomplete = () => t(), e.onerror = () => n(e.error), e.onabort = () => n(e.error || /* @__PURE__ */ Error("IndexedDB transaction aborted"));
+ });
+}
+function O(e, t, n) {
+ return IDBKeyRange.bound([e, t], [e, n]);
+}
+async function ee(e, t) {
+ let n = e.transaction(["files", "blocks"], "readwrite");
+ n.objectStore("files").delete(t), n.objectStore("blocks").delete(O(t, 0, Infinity)), await D(n);
+}
+async function k(e, t, n, r, i, a) {
+ let o = e.transaction(["files", "blocks"], "readwrite"), s = o.objectStore("files"), c = await E(s.get(t)), l = 0;
+ c && c.validator === n && c.totalSize === r && c.blockSize === i ? l = c.bytes : c && o.objectStore("blocks").delete(O(t, 0, Infinity)), s.put({
+ validator: n,
+ totalSize: r,
+ blockSize: i,
+ bytes: l,
+ lastUsed: Date.now()
+ }, t), await D(o);
+ let u = e.transaction("files", "readonly"), d = u.objectStore("files"), [f, p] = await Promise.all([E(d.getAllKeys()), E(d.getAll())]);
+ await D(u);
+ let m = p.reduce((e, t) => e + t.bytes, 0);
+ if (m <= a) return;
+ let h = f.map((e, t) => ({
+ key: e,
+ meta: p[t]
+ })).filter((e) => e.key !== t).sort((e, t) => e.meta.lastUsed - t.meta.lastUsed);
+ for (let t of h) {
+ if (m <= a) break;
+ await ee(e, t.key), m -= t.meta.bytes;
+ }
+}
+async function A(e, t) {
+ let { fileKey: n, validator: r, totalSize: i } = t, a = typeof t.options == "object" && t.options || {}, o = a.blockSize || x, s = a.maxBytes || S, c = a.dbName || C;
+ if (typeof indexedDB > "u" || !r) return e;
+ let l;
+ try {
+ l = await T(c), await k(l, n, r, i, o, s);
+ } catch {
+ return e;
+ }
+ let u = !1;
+ async function d(e, t) {
+ let r = l.transaction("blocks", "readonly"), i = r.objectStore("blocks"), a = O(n, e, t), [o, s] = await Promise.all([E(i.getAllKeys(a)), E(i.getAll(a))]);
+ await D(r);
+ let c = /* @__PURE__ */ new Map();
+ for (let e = 0; e < o.length; e++) c.set(o[e][1], s[e]);
+ return c;
+ }
+ async function f(e) {
+ if (!(u || e.length === 0)) try {
+ let t = l.transaction(["files", "blocks"], "readwrite"), r = t.objectStore("blocks"), i = t.objectStore("files");
+ for (let t of e) r.put(t.data, [n, t.index]);
+ let a = await E(i.get(n));
+ a && (a.bytes += e.reduce((e, t) => e + t.data.byteLength, 0), a.lastUsed = Date.now(), i.put(a, n)), await D(t);
+ } catch {
+ u = !0;
+ }
+ }
+ let p = (e) => Math.min(o, i - e * o), m = /* @__PURE__ */ new Map();
+ function h(e) {
+ let t, n, r = new Promise((e, r) => {
+ t = e, n = r;
+ });
+ return r.catch(() => {}), m.set(e, r), {
+ resolve: t,
+ reject: n,
+ promise: r
+ };
+ }
+ return async function(t, n, r, i) {
+ if (i === 0) return;
+ let a = Math.floor(r / o), s = Math.floor((r + i - 1) / o), c = await d(a, s), l = [], u = (e, a) => {
+ let s = a * o, c = Math.max(r, s), l = Math.min(r + i, s + p(a));
+ t.set(e.subarray(c - s, l - s), n + (c - r));
+ }, g = a;
+ for (; g <= s;) {
+ let a = g * o, d = a + p(g), f = c.get(g);
+ if (f) {
+ u(f, g), g++;
+ continue;
+ }
+ let _ = m.get(g);
+ if (_) {
+ u(await _, g), g++;
+ continue;
+ }
+ if (a >= r && d <= r + i) {
+ let u = g;
+ for (; u + 1 <= s && !c.get(u + 1) && !m.get(u + 1) && (u + 1) * o + p(u + 1) <= r + i;) u++;
+ let d = a, f = u * o + p(u), _ = [];
+ for (let e = g; e <= u; e++) _.push(h(e));
+ try {
+ await e(t, n + (d - r), d, f - d);
+ } catch (e) {
+ for (let t = g; t <= u; t++) _[t - g].reject(e), m.delete(t);
+ throw e;
+ }
+ for (let e = g; e <= u; e++) {
+ let i = e * o, a = t.slice(n + (i - r), n + (i - r) + p(e));
+ _[e - g].resolve(a), l.push({
+ index: e,
+ data: a
+ });
+ }
+ g = u + 1;
+ } else {
+ let t = h(g), n = new Uint8Array(p(g));
+ try {
+ await e(n, 0, a, n.length);
+ } catch (e) {
+ throw t.reject(e), m.delete(g), e;
+ }
+ t.resolve(n), u(n, g), l.push({
+ index: g,
+ data: n
+ }), g++;
+ }
+ }
+ await f(l);
+ for (let e of l) m.delete(e.index);
+ };
+}
+async function j(e) {
+ let t = (typeof e.options == "object" && e.options || {}).dbName || C;
+ if (typeof indexedDB > "u") return null;
+ try {
+ let n = (await T(t)).transaction("files", "readonly"), r = await E(n.objectStore("files").get(e.fileKey));
+ return await D(n), r ? {
+ validator: r.validator,
+ totalSize: r.totalSize,
+ blockSize: r.blockSize,
+ bytes: r.bytes
+ } : null;
+ } catch {
+ return null;
+ }
+}
+async function M(e) {
+ let { fileKey: t, validator: n, totalSize: r, data: i } = e, a = typeof e.options == "object" && e.options || {}, o = a.blockSize || x, s = a.maxBytes || S, c = a.dbName || C;
+ if (typeof indexedDB > "u" || !n) return !1;
+ try {
+ let e = await T(c);
+ await k(e, t, n, r, o, s);
+ let a = Math.ceil(r / o);
+ for (let n = 0; n < a; n += 64) {
+ let s = e.transaction("blocks", "readwrite"), c = s.objectStore("blocks");
+ for (let e = n; e < Math.min(n + 64, a); e++) {
+ let n = e * o;
+ c.put(i.slice(n, Math.min(n + o, r)), [t, e]);
+ }
+ await D(s);
+ }
+ let l = e.transaction("files", "readwrite"), u = l.objectStore("files"), d = await E(u.get(t));
+ return d && (d.bytes = r, d.lastUsed = Date.now(), u.put(d, t)), await D(l), !0;
+ } catch {
+ return !1;
+ }
+}
+//#endregion
+//#region src/httpfile.js
+var N = 65536;
+async function P(e) {
+ let n = e.url, r = e.cache ? await j({
+ fileKey: n,
+ options: e.cache
+ }) : null, i = { Range: "bytes=0-0" };
+ r && r.validator && (r.validator[0] === "\"" || r.validator.indexOf("W/") === 0 ? i["If-None-Match"] = r.validator : i["If-Modified-Since"] = r.validator);
+ let a;
+ try {
+ a = await fetch(n, { headers: i });
+ } catch (e) {
+ if (!("If-None-Match" in i) && !("If-Modified-Since" in i)) throw e;
+ a = await fetch(n, { headers: { Range: "bytes=0-0" } });
+ }
+ if (a.status === 304) return await K(a), await F(n, r.validator, r.totalSize, e);
+ if (a.status === 206) {
+ let t = a.headers.get("content-range"), r = t ? /\/(\d+)\s*$/.exec(t) : null;
+ if (r) {
+ let t = parseInt(r[1]);
+ return await a.arrayBuffer(), await F(n, L(a), t, e);
+ }
+ return await a.arrayBuffer(), await I(n);
+ }
+ if (!a.ok && a.status !== 416) throw Error("HTTP " + a.status + " fetching " + n);
+ if (a.status === 416) {
+ let e = a.headers.get("content-range");
+ return e && /\/0\s*$/.test(e) ? t({
+ type: "mem",
+ data: /* @__PURE__ */ new Uint8Array()
+ }) : await I(n);
+ }
+ let o = new Uint8Array(await a.arrayBuffer());
+ if (e.cache) {
+ let t = L(a);
+ t && await M({
+ fileKey: n,
+ validator: t,
+ totalSize: o.length,
+ options: e.cache,
+ data: o
+ });
+ }
+ return t({
+ type: "mem",
+ data: o
+ });
+}
+async function F(e, t, n, r) {
+ let i = null, a = async function(n, r, a, o) {
+ if (!i) try {
+ return await W(e, t, n, r, a, o);
+ } catch (e) {
+ if (!e || !e.degradeToFull) throw e;
+ i = e.fullBodyPromise;
+ }
+ let s = await i;
+ if (a + o > s.byteLength) throw Error(e + ": read past the end of the buffered body");
+ n.set(s.subarray(a, a + o), r);
+ }, o = Math.min(r.pageSize || N, N);
+ return r.cache && (a = await A(a, {
+ fileKey: e,
+ validator: t,
+ totalSize: n,
+ options: r.cache
+ })), new y(a, n, r.cacheSize, o);
+}
+async function I(e) {
+ let n = await fetch(e);
+ if (!n.ok) throw Error("HTTP " + n.status + " fetching " + e);
+ return t({
+ type: "mem",
+ data: new Uint8Array(await n.arrayBuffer())
+ });
+}
+function L(e) {
+ let t = e.headers.get("etag");
+ return t && t.indexOf("W/") !== 0 ? t : e.headers.get("last-modified") || null;
+}
+var R = 4, z = 0, B = [];
+async function V(e) {
+ for (; z >= R;) await new Promise((e) => B.push(e));
+ z++;
+ try {
+ return await e();
+ } finally {
+ z--;
+ let e = B.shift();
+ e && e();
+ }
+}
+var H = {
+ retries: 3,
+ backoffMs: 300,
+ stallTimeoutMs: 1e4
+}, U = (e) => new Promise((t) => setTimeout(t, e));
+async function W(e, t, n, r, i, a) {
+ return V(async () => {
+ for (let o = 0;; o++) try {
+ return await G(e, t, n, r, i, a);
+ } catch (e) {
+ if (e && (e.degradeToFull || e.permanent) || o >= H.retries) throw e;
+ await U(H.backoffMs * (1 << o));
+ }
+ });
+}
+async function G(e, t, n, r, i, a) {
+ let o = { Range: "bytes=" + i + "-" + (i + a - 1) };
+ t && (o["If-Range"] = t);
+ let s = typeof AbortController < "u" ? new AbortController() : null, c = null, l = () => {
+ s && (c && clearTimeout(c), c = setTimeout(() => s.abort(/* @__PURE__ */ Error(e + ": no data for " + H.stallTimeoutMs + "ms")), H.stallTimeoutMs));
+ }, u = () => {
+ c && clearTimeout(c), c = null;
+ };
+ l();
+ let d;
+ try {
+ d = await fetch(e, s ? {
+ headers: o,
+ signal: s.signal
+ } : { headers: o });
+ } catch (e) {
+ throw u(), e;
+ }
+ if (l(), d.status === 200) {
+ let n = L(d);
+ if (!t || n && n === t) {
+ u();
+ let t = /* @__PURE__ */ Error(e + ": origin ignored Range; degrading to full buffering");
+ throw t.degradeToFull = !0, t.fullBodyPromise = d.arrayBuffer().then((e) => new Uint8Array(e)), t;
+ }
+ u(), await K(d);
+ let r = /* @__PURE__ */ Error(e + ": file changed (or server stopped honoring Range) while reading");
+ throw r.permanent = !0, r;
+ }
+ if (d.status !== 206) {
+ u(), await K(d);
+ let t = /* @__PURE__ */ Error("HTTP " + d.status + " reading range " + i + "+" + a + " of " + e);
+ throw d.status < 500 && d.status !== 429 && (t.permanent = !0), t;
+ }
+ let f = d.headers.get("content-range"), p = f ? /bytes\s+(\d+)-(\d+)\//.exec(f) : null;
+ if (p && parseInt(p[1]) !== i) throw await K(d), Error(e + ": server returned range starting at " + p[1] + ", requested " + i);
+ let m = 0;
+ try {
+ if (d.body && typeof d.body.getReader == "function") {
+ let t = d.body.getReader();
+ for (;;) {
+ let i = await t.read();
+ if (l(), i.done) break;
+ if (m + i.value.byteLength > a) throw t.cancel().catch(function() {}), Error(e + ": range response longer than requested");
+ n.set(i.value, r + m), m += i.value.byteLength;
+ }
+ } else {
+ /* c8 ignore start */
+ let t = new Uint8Array(await d.arrayBuffer());
+ if (t.byteLength > a) throw Error(e + ": range response longer than requested");
+ n.set(t, r), m = t.byteLength;
+ }
+ } finally {
+ u();
+ }
+ if (m !== a) throw Error(e + ": short range response (" + m + "/" + a + " bytes at " + i + ")");
+}
+async function K(e) {
+ try {
+ e.body && typeof e.body.cancel == "function" ? await e.body.cancel() : await e.arrayBuffer();
+ } catch {}
+}
+//#endregion
+//#region src/blobfile.js
+var q = 1 << 20;
+function J(e) {
+ let t = e.blob, n = async function(e, n, r, i) {
+ let a = await t.slice(r, r + i).arrayBuffer();
+ if (a.byteLength !== i) throw Error("short blob read (" + a.byteLength + "/" + i + " bytes at " + r + ")");
+ e.set(new Uint8Array(a), n);
+ }, r = Math.min(e.pageSize || q, q);
+ return new y(n, t.size, e.cacheSize, r);
+}
+//#endregion
+//#region src/fastfile.browser.js
+function Y() {
+ throw Error("File I/O is not supported in the browser");
+}
+function X(e) {
+ return e instanceof Uint8Array ? {
+ type: "mem",
+ data: e
+ } : (typeof e == "string" && Y(), e);
+}
+function Z(e, t, n) {
+ if (e.type === "file" && Y(), e.type === "mem") return t(e);
+ if (e.type === "bigMem") return n(e);
+ throw Error("Invalid FastFile type: " + e.type);
+}
+function Q(t) {
+ return Z(X(t), e, l);
+}
+var te = Q;
+async function ne(e, n, r) {
+ return e instanceof Uint8Array && (e = {
+ type: "mem",
+ data: e
+ }), typeof Blob < "u" && e instanceof Blob && (e = {
+ type: "blob",
+ blob: e,
+ cacheSize: n,
+ pageSize: r
+ }), typeof e == "string" && (e = {
+ type: "http",
+ url: e,
+ cacheSize: n,
+ pageSize: r
+ }), e.type === "http" ? await P(e) : e.type === "blob" ? J(e) : Z(e, t, u);
+}
+function $(e) {
+ return typeof e == "string" && Y(), Z(e, n, d);
+}
+var re = $;
+//#endregion
+export { te as createNoOverride, Q as createOverride, ne as readExisting, $ as readWriteExisting, re as readWriteExistingOrCreate };
diff --git a/build/browser/browser.iife.js b/build/browser/browser.iife.js
new file mode 100644
index 0000000..cbe3261
--- /dev/null
+++ b/build/browser/browser.iife.js
@@ -0,0 +1 @@
+var fastfile=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){let t=e.initialSize||1<<20,n=new c;return n.o=e,n.o.data=new Uint8Array(t),n.allocSize=t,n.totalSize=0,n.readOnly=!1,n.pos=0,n}function n(e){let t=new c;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!0,t.pos=0,t}function r(e){let t=new c;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!1,t.pos=0,t}var i=new Uint8Array(4),a=new DataView(i.buffer),o=new Uint8Array(8),s=new DataView(o.buffer),c=class{constructor(){this.pageSize=16384}_resizeIfNeeded(e){if(e>this.allocSize){let t=Math.max(this.allocSize+(1<<20),Math.floor(this.allocSize*1.1),e),n=new Uint8Array(t);n.set(this.o.data),this.o.data=n,this.allocSize=t}}async write(e,t){let n=this;if(t===void 0&&(t=n.pos),this.readOnly)throw Error(`Writing a read only file`);this._resizeIfNeeded(t+e.byteLength),this.o.data.set(e.slice(),t),t+e.byteLength>this.totalSize&&(this.totalSize=t+e.byteLength),this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+r,n);e.set(a,t),this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(e,t){let n=this;a.setUint32(0,e,!0),await n.write(i,t)}async writeUBE32(e,t){let n=this;a.setUint32(0,e,!1),await n.write(i,t)}async writeULE64(e,t){let n=this;s.setUint32(0,e&4294967295,!0),s.setUint32(4,Math.floor(e/4294967296),!0),await n.write(o,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>=this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);return``}let r=new Uint8Array(t.o.data.buffer,n,this.totalSize-n),i=r.findIndex(e=>e===0),a=i!==-1,o=``;return a?(o=new TextDecoder().decode(r.slice(0,i)),t.pos=n+i+1):t.pos=n,o}},l=1<<22;function u(e){let t=e.initialSize||0,n=new _;n.o=e;let r=t?Math.floor((t-1)/l)+1:0;n.o.data=[];for(let e=0;e0;){let t=i+a>l?l-i:a,o=e.slice(e.byteLength-a,e.byteLength-a+t);new Uint8Array(n.o.data[r].buffer,i,t).set(o),a-=t,r++,i=0}this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=Math.floor(r/l),o=r%l,s=n;for(;s>0;){let r=o+s>l?l-o:s,c=new Uint8Array(i.o.data[a].buffer,o,r);e.set(c,t+n-s),s-=r,a++,o=0}this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){}async discard(){}async writeULE32(e,t){let n=this;m.setUint32(0,e,!0),await n.write(p,t)}async writeUBE32(e,t){let n=this;m.setUint32(0,e,!1),await n.write(p,t)}async writeULE64(e,t){let n=this;g.setUint32(0,e&4294967295,!0),g.setUint32(4,Math.floor(e/4294967296),!0),await n.write(h,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=!1,i=``;for(;!r;){let e=Math.floor(n/l),a=n%l;if(t.o.data[e]===void 0)throw Error(`ERROR`);let o=Math.min(2048,t.o.data[e].length-a);if(o<=0)return t.pos=n,i;let s=new Uint8Array(t.o.data[e].buffer,a,o),c=s.findIndex(e=>e===0);r=c!==-1,r?(i+=new TextDecoder().decode(s.slice(0,c)),t.pos=e*l+a+c+1):(i+=new TextDecoder().decode(s),t.pos=e*l+a+s.length),n=t.pos}return i}},v=1<<20,y=8192,b=class{constructor(e,t,n,r){this.readRangeInto=e,this.totalSize=t,this.pos=0,this.pageSize=r||y,this.maxPagesLoaded=Math.floor((n||v)/this.pageSize)+1,this.pages=new Map,this.readOnly=!0}_pageLen(e){let t=e*this.pageSize;return Math.min(t+this.pageSize,this.totalSize)-t}_loadPage(e){let t=this,n=t.pages.get(e);if(n)return t.pages.delete(e),t.pages.set(e,n),n.promise;let r=new Uint8Array(t._pageLen(e));return n={buff:null,promise:null},n.promise=t.readRangeInto(r,0,e*t.pageSize,r.byteLength).then(function(){return n.buff=r,r},function(n){throw t.pages.delete(e),n}),t.pages.set(e,n),t._trimCache(),n.promise}_trimCache(){let e=this;if(!(e.pages.size<=e.maxPagesLoaded))for(let t of e.pages){if(e.pages.size<=e.maxPagesLoaded)return;t[1].buff&&e.pages.delete(t[0])}}async readToBuffer(e,t,n,r){let i=this;if(n===0)return;if(i.pendingClose)throw Error(`Reading a closing file`);if(r===void 0&&(r=i.pos),r+n>i.totalSize)throw Error(`Reading out of bounds`);if(i.pos=r+n,n>=i.pageSize){await i.readRangeInto(e,t,r,n);return}let a=Math.floor(r/i.pageSize),o=Math.floor((r+n-1)/i.pageSize),s=r%i.pageSize,c=0;for(let r=a;r<=o;r++){let a=await i._loadPage(r),o=Math.min(n-c,i.pageSize-s);e.set(a.subarray(s,s+o),t+c),c+=o,s=0}}async read(e,t){let n=new Uint8Array(e);return await this.readToBuffer(n,0,e,t),n}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this;if(t.pendingClose)throw Error(`Reading a closing file`);let n=e===void 0?t.pos:e,r=[];for(;n=0)return r.push(i.subarray(0,a)),t.pos=n+a+1,x(r);r.push(i),n+=e}return t.pos=n,x(r)}async write(){throw Error(`Writing a read only file`)}async writeULE32(){throw Error(`Writing a read only file`)}async writeUBE32(){throw Error(`Writing a read only file`)}async writeULE64(){throw Error(`Writing a read only file`)}async close(){this.pendingClose||(this.pendingClose=!0,this.pages.clear())}async discard(){await this.close()}};function x(e){let t=0;for(let n=0;n{let r=indexedDB.open(e,1);r.onupgradeneeded=()=>{let e=r.result;e.createObjectStore(`files`),e.createObjectStore(`blocks`)},r.onsuccess=()=>t(r.result),r.onerror=()=>n(r.error),r.onblocked=()=>n(Error(`IndexedDB open blocked`))});return T.set(e,t),t.catch(()=>T.delete(e)),t}function D(e){return new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)})}function O(e){return new Promise((t,n)=>{e.oncomplete=()=>t(),e.onerror=()=>n(e.error),e.onabort=()=>n(e.error||Error(`IndexedDB transaction aborted`))})}function k(e,t,n){return IDBKeyRange.bound([e,t],[e,n])}async function ee(e,t){let n=e.transaction([`files`,`blocks`],`readwrite`);n.objectStore(`files`).delete(t),n.objectStore(`blocks`).delete(k(t,0,1/0)),await O(n)}async function A(e,t,n,r,i,a){let o=e.transaction([`files`,`blocks`],`readwrite`),s=o.objectStore(`files`),c=await D(s.get(t)),l=0;c&&c.validator===n&&c.totalSize===r&&c.blockSize===i?l=c.bytes:c&&o.objectStore(`blocks`).delete(k(t,0,1/0)),s.put({validator:n,totalSize:r,blockSize:i,bytes:l,lastUsed:Date.now()},t),await O(o);let u=e.transaction(`files`,`readonly`),d=u.objectStore(`files`),[f,p]=await Promise.all([D(d.getAllKeys()),D(d.getAll())]);await O(u);let m=p.reduce((e,t)=>e+t.bytes,0);if(m<=a)return;let h=f.map((e,t)=>({key:e,meta:p[t]})).filter(e=>e.key!==t).sort((e,t)=>e.meta.lastUsed-t.meta.lastUsed);for(let t of h){if(m<=a)break;await ee(e,t.key),m-=t.meta.bytes}}async function j(e,t){let{fileKey:n,validator:r,totalSize:i}=t,a=typeof t.options==`object`&&t.options||{},o=a.blockSize||S,s=a.maxBytes||C,c=a.dbName||w;if(typeof indexedDB>`u`||!r)return e;let l;try{l=await E(c),await A(l,n,r,i,o,s)}catch{return e}let u=!1;async function d(e,t){let r=l.transaction(`blocks`,`readonly`),i=r.objectStore(`blocks`),a=k(n,e,t),[o,s]=await Promise.all([D(i.getAllKeys(a)),D(i.getAll(a))]);await O(r);let c=new Map;for(let e=0;ee+t.data.byteLength,0),a.lastUsed=Date.now(),i.put(a,n)),await O(t)}catch{u=!0}}let p=e=>Math.min(o,i-e*o),m=new Map;function h(e){let t,n,r=new Promise((e,r)=>{t=e,n=r});return r.catch(()=>{}),m.set(e,r),{resolve:t,reject:n,promise:r}}return async function(t,n,r,i){if(i===0)return;let a=Math.floor(r/o),s=Math.floor((r+i-1)/o),c=await d(a,s),l=[],u=(e,a)=>{let s=a*o,c=Math.max(r,s),l=Math.min(r+i,s+p(a));t.set(e.subarray(c-s,l-s),n+(c-r))},g=a;for(;g<=s;){let a=g*o,d=a+p(g),f=c.get(g);if(f){u(f,g),g++;continue}let _=m.get(g);if(_){u(await _,g),g++;continue}if(a>=r&&d<=r+i){let u=g;for(;u+1<=s&&!c.get(u+1)&&!m.get(u+1)&&(u+1)*o+p(u+1)<=r+i;)u++;let d=a,f=u*o+p(u),_=[];for(let e=g;e<=u;e++)_.push(h(e));try{await e(t,n+(d-r),d,f-d)}catch(e){for(let t=g;t<=u;t++)_[t-g].reject(e),m.delete(t);throw e}for(let e=g;e<=u;e++){let i=e*o,a=t.slice(n+(i-r),n+(i-r)+p(e));_[e-g].resolve(a),l.push({index:e,data:a})}g=u+1}else{let t=h(g),n=new Uint8Array(p(g));try{await e(n,0,a,n.length)}catch(e){throw t.reject(e),m.delete(g),e}t.resolve(n),u(n,g),l.push({index:g,data:n}),g++}}await f(l);for(let e of l)m.delete(e.index)}}async function M(e){let t=(typeof e.options==`object`&&e.options||{}).dbName||w;if(typeof indexedDB>`u`)return null;try{let n=(await E(t)).transaction(`files`,`readonly`),r=await D(n.objectStore(`files`).get(e.fileKey));return await O(n),r?{validator:r.validator,totalSize:r.totalSize,blockSize:r.blockSize,bytes:r.bytes}:null}catch{return null}}async function N(e){let{fileKey:t,validator:n,totalSize:r,data:i}=e,a=typeof e.options==`object`&&e.options||{},o=a.blockSize||S,s=a.maxBytes||C,c=a.dbName||w;if(typeof indexedDB>`u`||!n)return!1;try{let e=await E(c);await A(e,t,n,r,o,s);let a=Math.ceil(r/o);for(let n=0;ns.byteLength)throw Error(e+`: read past the end of the buffered body`);n.set(s.subarray(a,a+o),r)},o=Math.min(r.pageSize||P,P);return r.cache&&(a=await j(a,{fileKey:e,validator:t,totalSize:n,options:r.cache})),new b(a,n,r.cacheSize,o)}async function L(e){let t=await fetch(e);if(!t.ok)throw Error(`HTTP `+t.status+` fetching `+e);return n({type:`mem`,data:new Uint8Array(await t.arrayBuffer())})}function R(e){let t=e.headers.get(`etag`);return t&&t.indexOf(`W/`)!==0?t:e.headers.get(`last-modified`)||null}var z=4,B=0,V=[];async function te(e){for(;B>=z;)await new Promise(e=>V.push(e));B++;try{return await e()}finally{B--;let e=V.shift();e&&e()}}var H={retries:3,backoffMs:300,stallTimeoutMs:1e4},U=e=>new Promise(t=>setTimeout(t,e));async function W(e,t,n,r,i,a){return te(async()=>{for(let o=0;;o++)try{return await G(e,t,n,r,i,a)}catch(e){if(e&&(e.degradeToFull||e.permanent)||o>=H.retries)throw e;await U(H.backoffMs*(1<{s&&(c&&clearTimeout(c),c=setTimeout(()=>s.abort(Error(e+`: no data for `+H.stallTimeoutMs+`ms`)),H.stallTimeoutMs))},u=()=>{c&&clearTimeout(c),c=null};l();let d;try{d=await fetch(e,s?{headers:o,signal:s.signal}:{headers:o})}catch(e){throw u(),e}if(l(),d.status===200){let n=R(d);if(!t||n&&n===t){u();let t=Error(e+`: origin ignored Range; degrading to full buffering`);throw t.degradeToFull=!0,t.fullBodyPromise=d.arrayBuffer().then(e=>new Uint8Array(e)),t}u(),await K(d);let r=Error(e+`: file changed (or server stopped honoring Range) while reading`);throw r.permanent=!0,r}if(d.status!==206){u(),await K(d);let t=Error(`HTTP `+d.status+` reading range `+i+`+`+a+` of `+e);throw d.status<500&&d.status!==429&&(t.permanent=!0),t}let f=d.headers.get(`content-range`),p=f?/bytes\s+(\d+)-(\d+)\//.exec(f):null;if(p&&parseInt(p[1])!==i)throw await K(d),Error(e+`: server returned range starting at `+p[1]+`, requested `+i);let m=0;try{if(d.body&&typeof d.body.getReader==`function`){let t=d.body.getReader();for(;;){let i=await t.read();if(l(),i.done)break;if(m+i.value.byteLength>a)throw t.cancel().catch(function(){}),Error(e+`: range response longer than requested`);n.set(i.value,r+m),m+=i.value.byteLength}}else{let t=new Uint8Array(await d.arrayBuffer());if(t.byteLength>a)throw Error(e+`: range response longer than requested`);n.set(t,r),m=t.byteLength}}finally{u()}if(m!==a)throw Error(e+`: short range response (`+m+`/`+a+` bytes at `+i+`)`)}async function K(e){try{e.body&&typeof e.body.cancel==`function`?await e.body.cancel():await e.arrayBuffer()}catch{}}var q=1<<20;function J(e){let t=e.blob,n=async function(e,n,r,i){let a=await t.slice(r,r+i).arrayBuffer();if(a.byteLength!==i)throw Error(`short blob read (`+a.byteLength+`/`+i+` bytes at `+r+`)`);e.set(new Uint8Array(a),n)},r=Math.min(e.pageSize||q,q);return new b(n,t.size,e.cacheSize,r)}function Y(){throw Error(`File I/O is not supported in the browser`)}function X(e){return e instanceof Uint8Array?{type:`mem`,data:e}:(typeof e==`string`&&Y(),e)}function Z(e,t,n){if(e.type===`file`&&Y(),e.type===`mem`)return t(e);if(e.type===`bigMem`)return n(e);throw Error(`Invalid FastFile type: `+e.type)}function Q(e){return Z(X(e),t,u)}var ne=Q;async function re(e,t,r){return e instanceof Uint8Array&&(e={type:`mem`,data:e}),typeof Blob<`u`&&e instanceof Blob&&(e={type:`blob`,blob:e,cacheSize:t,pageSize:r}),typeof e==`string`&&(e={type:`http`,url:e,cacheSize:t,pageSize:r}),e.type===`http`?await F(e):e.type===`blob`?J(e):Z(e,n,d)}function $(e){return typeof e==`string`&&Y(),Z(e,r,f)}var ie=$;return e.createNoOverride=ne,e.createOverride=Q,e.readExisting=re,e.readWriteExisting=$,e.readWriteExistingOrCreate=ie,e})({});
\ No newline at end of file
diff --git a/build/main.cjs b/build/main.cjs
deleted file mode 100644
index 260d9c9..0000000
--- a/build/main.cjs
+++ /dev/null
@@ -1,1029 +0,0 @@
-'use strict';
-
-Object.defineProperty(exports, '__esModule', { value: true });
-
-var fs = require('fs');
-var constants = require('constants');
-
-function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
-
-var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
-
-async function open(fileName, openFlags, cacheSize, pageSize) {
- cacheSize = cacheSize || 4096*64;
- if (typeof openFlags !== "number" && ["w+", "wx+", "r", "ax+", "a+"].indexOf(openFlags) <0)
- throw new Error("Invalid open option");
- const fd =await fs__default["default"].promises.open(fileName, openFlags);
-
- const stats = await fd.stat();
-
- return new FastFile(fd, stats, cacheSize, pageSize, fileName);
-}
-
-
-class FastFile {
-
- constructor(fd, stats, cacheSize, pageSize, fileName) {
- this.fileName = fileName;
- this.fd = fd;
- this.pos = 0;
- this.pageSize = pageSize || (1 << 8);
- while (this.pageSize < stats.blksize) {
- this.pageSize *= 2;
- }
- this.totalSize = stats.size;
- this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1;
- this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1;
- this.pages = {};
- this.pendingLoads = [];
- this.writing = false;
- this.reading = false;
- this.avBuffs = [];
- this.history = {};
- }
-
- _loadPage(p) {
- const self = this;
- const P = new Promise((resolve, reject)=> {
- self.pendingLoads.push({
- page: p,
- resolve: resolve,
- reject: reject
- });
- });
- self.__statusPage("After Load request: ", p);
- return P;
- }
-
- __statusPage(s, p) {
- const logEntry = [];
- const self=this;
- if (!self.logHistory) return;
- logEntry.push("==" + s+ " " +p);
- let S = "";
- for (let i=0; i " + self.history[p][i][j]);
- }
- }
- }
-
-
-
- _triggerLoad() {
- const self = this;
-
- if (self.reading) return;
- if (self.pendingLoads.length==0) return;
-
- const pageIdxs = Object.keys(self.pages);
-
- const deletablePages = [];
- for (let i=0; i0) &&
- ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" )
- ||( (freePages>0)
- ||(deletablePages.length>0)))) {
- const load = self.pendingLoads.shift();
- if (typeof self.pages[load.page] != "undefined") {
- self.pages[load.page].pendingOps ++;
- const idx = deletablePages.indexOf(load.page);
- if (idx>=0) deletablePages.splice(idx, 1);
- if (self.pages[load.page].loading) {
- self.pages[load.page].loading.push(load);
- } else {
- load.resolve();
- }
- self.__statusPage("After Load (cached): ", load.page);
-
- } else {
- if (freePages) {
- freePages--;
- } else {
- const fp = deletablePages.shift();
- self.__statusPage("Before Unload: ", fp);
- self.avBuffs.unshift(self.pages[fp]);
- delete self.pages[fp];
- self.__statusPage("After Unload: ", fp);
- }
-
- if (load.page>=self.totalPages) {
- self.pages[load.page] = getNewPage();
- load.resolve();
- self.__statusPage("After Load (new): ", load.page);
- } else {
- self.reading = true;
- self.pages[load.page] = getNewPage();
- self.pages[load.page].loading = [load];
- ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> {
- self.pages[load.page].size = res.bytesRead;
- const loading = self.pages[load.page].loading;
- delete self.pages[load.page].loading;
- for (let i=0; i {
- load.reject(err);
- }));
- self.__statusPage("After Load (loading): ", load.page);
- }
- }
- }
- // if (ops.length>1) console.log(ops.length);
-
- Promise.all(ops).then( () => {
- self.reading = false;
- if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self));
- self._tryClose();
- });
-
- function getNewPage() {
- if (self.avBuffs.length>0) {
- const p = self.avBuffs.shift();
- p.dirty = false;
- p.pendingOps = 1;
- p.size =0;
- return p;
- } else {
- return {
- dirty: false,
- buff: new Uint8Array(self.pageSize),
- pendingOps: 1,
- size: 0
- };
- }
- }
-
- }
-
-
- _triggerWrite() {
- const self = this;
- if (self.writing) return;
-
- const pageIdxs = Object.keys(self.pages);
-
- const ops = [];
-
- for (let i=0; i {
- page.writing = false;
- return;
- }, (err) => {
- console.log("ERROR Writing: "+err);
- self.error = err;
- self._tryClose();
- }));
- }
- }
-
- if (self.writing) {
- Promise.all(ops).then( () => {
- self.writing = false;
- setImmediate(self._triggerWrite.bind(self));
- self._tryClose();
- if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self));
- });
- }
- }
-
- _getDirtyPage() {
- for (let p in this.pages) {
- if (this.pages[p].dirty) return p;
- }
- return -1;
- }
-
- async write(buff, pos) {
- if (buff.byteLength == 0) return;
- const self = this;
- /*
- if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) {
- const cacheSize = Math.floor(buff.byteLength * 1.1);
- this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1;
- }
- */
- if (typeof pos == "undefined") pos = self.pos;
- self.pos = pos+buff.byteLength;
- if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength;
- if (self.pendingClose)
- throw new Error("Writing a closing file");
- const firstPage = Math.floor(pos / self.pageSize);
- const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize);
-
- const pagePromises = [];
- for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i));
- self._triggerLoad();
-
- let p = firstPage;
- let o = pos % self.pageSize;
- let r = buff.byteLength;
- while (r>0) {
- await pagePromises[p-firstPage];
- const l = (o+r > self.pageSize) ? (self.pageSize -o) : r;
- const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l);
- const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l);
- dstView.set(srcView);
- self.pages[p].dirty = true;
- self.pages[p].pendingOps --;
- self.pages[p].size = Math.max(o+l, self.pages[p].size);
- if (p>=self.totalPages) {
- self.totalPages = p+1;
- }
- r = r-l;
- p ++;
- o = 0;
- if (!self.writing) setImmediate(self._triggerWrite.bind(self));
- }
- }
-
- async read(len, pos) {
- const self = this;
- let buff = new Uint8Array(len);
- await self.readToBuffer(buff, 0, len, pos);
-
- return buff;
- }
-
- async readToBuffer(buffDst, offset, len, pos) {
- if (len == 0) {
- return;
- }
- const self = this;
- if (len > self.pageSize*self.maxPagesLoaded*0.8) {
- const cacheSize = Math.floor(len * 1.1);
- this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1;
- }
- if (typeof pos == "undefined") pos = self.pos;
- self.pos = pos+len;
- if (self.pendingClose)
- throw new Error("Reading a closing file");
- const firstPage = Math.floor(pos / self.pageSize);
- const lastPage = Math.floor((pos + len -1) / self.pageSize);
-
- const pagePromises = [];
- for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i));
-
- self._triggerLoad();
-
- let p = firstPage;
- let o = pos % self.pageSize;
- // Remaining bytes to read
- let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len;
- while (r>0) {
- await pagePromises[p - firstPage];
- self.__statusPage("After Await (read): ", p);
-
- // bytes to copy from this page
- const l = (o+r > self.pageSize) ? (self.pageSize -o) : r;
- const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l);
- buffDst.set(srcView, offset+len-r);
- self.pages[p].pendingOps --;
-
- self.__statusPage("After Op done: ", p);
-
- r = r-l;
- p ++;
- o = 0;
- if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self));
- }
-
- this.pos = pos + len;
-
- }
-
-
- _tryClose() {
- const self = this;
- if (!self.pendingClose) return;
- if (self.error) {
- self.pendingCloseReject(self.error);
- }
- const p = self._getDirtyPage();
- if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return;
- self.pendingClose();
- }
-
- close() {
- const self = this;
- if (self.pendingClose)
- throw new Error("Closing the file twice");
- return new Promise((resolve, reject) => {
- self.pendingClose = resolve;
- self.pendingCloseReject = reject;
- self._tryClose();
- }).then(()=> {
- self.fd.close();
- }, (err) => {
- self.fd.close();
- throw (err);
- });
- }
-
- async discard() {
- const self = this;
- await self.close();
- await fs__default["default"].promises.unlink(this.fileName);
- }
-
- async writeULE32(v, pos) {
- const self = this;
- const tmpBuff32 = new Uint8Array(4);
- const tmpBuff32v = new DataView(tmpBuff32.buffer);
-
- tmpBuff32v.setUint32(0, v, true);
-
- await self.write(tmpBuff32, pos);
- }
-
- async writeUBE32(v, pos) {
- const self = this;
-
- const tmpBuff32 = new Uint8Array(4);
- const tmpBuff32v = new DataView(tmpBuff32.buffer);
-
- tmpBuff32v.setUint32(0, v, false);
-
- await self.write(tmpBuff32, pos);
- }
-
-
- async writeULE64(v, pos) {
- const self = this;
-
- const tmpBuff64 = new Uint8Array(8);
- const tmpBuff64v = new DataView(tmpBuff64.buffer);
-
- tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true);
- tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true);
-
- await self.write(tmpBuff64, pos);
- }
-
- async readULE32(pos) {
- const self = this;
- const b = await self.read(4, pos);
-
- const view = new Uint32Array(b.buffer);
-
- return view[0];
- }
-
- async readUBE32(pos) {
- const self = this;
- const b = await self.read(4, pos);
-
- const view = new DataView(b.buffer);
-
- return view.getUint32(0, false);
- }
-
- async readULE64(pos) {
- const self = this;
- const b = await self.read(8, pos);
-
- const view = new Uint32Array(b.buffer);
-
- return view[1] * 0x100000000 + view[0];
- }
-
- async readString(pos) {
- const self = this;
-
- if (self.pendingClose) {
- throw new Error("Reading a closing file");
- }
-
- let currentPosition = typeof pos == "undefined" ? self.pos : pos;
- let currentPage = Math.floor(currentPosition / self.pageSize);
-
- let endOfStringFound = false;
- let str = "";
-
- while (!endOfStringFound) {
- //Read page
- let pagePromise = self._loadPage(currentPage);
- self._triggerLoad();
- await pagePromise;
- self.__statusPage("After Await (read): ", currentPage);
-
- let offsetOnPage = currentPosition % self.pageSize;
-
- const dataArray = new Uint8Array(
- self.pages[currentPage].buff.buffer,
- self.pages[currentPage].buff.byteOffset + offsetOnPage,
- self.pageSize - offsetOnPage
- );
-
- let indexEndOfString = dataArray.findIndex(element => element === 0);
- endOfStringFound = indexEndOfString !== -1;
-
- if (endOfStringFound) {
- str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString));
- self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1;
- } else {
- str += new TextDecoder().decode(dataArray);
- self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length;
- }
-
- self.pages[currentPage].pendingOps--;
- self.__statusPage("After Op done: ", currentPage);
-
- currentPosition = self.pos;
- currentPage++;
-
- if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self));
- }
-
- return str;
- }
-}
-
-function createNew$1(o) {
- const initialSize = o.initialSize || 1<<20;
- const fd = new MemFile();
- fd.o = o;
- fd.o.data = new Uint8Array(initialSize);
- fd.allocSize = initialSize;
- fd.totalSize = 0;
- fd.readOnly = false;
- fd.pos = 0;
- return fd;
-}
-
-function readExisting$2(o) {
- const fd = new MemFile();
- fd.o = o;
- fd.allocSize = o.data.byteLength;
- fd.totalSize = o.data.byteLength;
- fd.readOnly = true;
- fd.pos = 0;
- return fd;
-}
-
-function readWriteExisting$2(o) {
- const fd = new MemFile();
- fd.o = o;
- fd.allocSize = o.data.byteLength;
- fd.totalSize = o.data.byteLength;
- fd.readOnly = false;
- fd.pos = 0;
- return fd;
-}
-
-const tmpBuff32$1 = new Uint8Array(4);
-const tmpBuff32v$1 = new DataView(tmpBuff32$1.buffer);
-const tmpBuff64$1 = new Uint8Array(8);
-const tmpBuff64v$1 = new DataView(tmpBuff64$1.buffer);
-
-class MemFile {
-
- constructor() {
- this.pageSize = 1 << 14; // for compatibility
- }
-
- _resizeIfNeeded(newLen) {
- if (newLen > this.allocSize) {
- const newAllocSize = Math.max(
- this.allocSize + (1 << 20),
- Math.floor(this.allocSize * 1.1),
- newLen
- );
- const newData = new Uint8Array(newAllocSize);
- newData.set(this.o.data);
- this.o.data = newData;
- this.allocSize = newAllocSize;
- }
- }
-
- async write(buff, pos) {
- const self =this;
- if (typeof pos == "undefined") pos = self.pos;
- if (this.readOnly) throw new Error("Writing a read only file");
-
- this._resizeIfNeeded(pos + buff.byteLength);
-
- this.o.data.set(buff.slice(), pos);
-
- if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength;
-
- this.pos = pos + buff.byteLength;
- }
-
- async readToBuffer(buffDest, offset, len, pos) {
- const self = this;
- if (typeof pos == "undefined") pos = self.pos;
- if (this.readOnly) {
- if (pos + len > this.totalSize) throw new Error("Reading out of bounds");
- }
- this._resizeIfNeeded(pos + len);
-
- const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len);
-
- buffDest.set(buffSrc, offset);
-
- this.pos = pos + len;
- }
-
- async read(len, pos) {
- const self = this;
-
- const buff = new Uint8Array(len);
- await self.readToBuffer(buff, 0, len, pos);
-
- return buff;
- }
-
- close() {
- if (this.o.data.byteLength != this.totalSize) {
- this.o.data = this.o.data.slice(0, this.totalSize);
- }
- }
-
- async discard() {
- }
-
-
- async writeULE32(v, pos) {
- const self = this;
-
- tmpBuff32v$1.setUint32(0, v, true);
-
- await self.write(tmpBuff32$1, pos);
- }
-
- async writeUBE32(v, pos) {
- const self = this;
-
- tmpBuff32v$1.setUint32(0, v, false);
-
- await self.write(tmpBuff32$1, pos);
- }
-
-
- async writeULE64(v, pos) {
- const self = this;
-
- tmpBuff64v$1.setUint32(0, v & 0xFFFFFFFF, true);
- tmpBuff64v$1.setUint32(4, Math.floor(v / 0x100000000) , true);
-
- await self.write(tmpBuff64$1, pos);
- }
-
-
- async readULE32(pos) {
- const self = this;
- const b = await self.read(4, pos);
-
- const view = new Uint32Array(b.buffer);
-
- return view[0];
- }
-
- async readUBE32(pos) {
- const self = this;
- const b = await self.read(4, pos);
-
- const view = new DataView(b.buffer);
-
- return view.getUint32(0, false);
- }
-
- async readULE64(pos) {
- const self = this;
- const b = await self.read(8, pos);
-
- const view = new Uint32Array(b.buffer);
-
- return view[1] * 0x100000000 + view[0];
- }
-
- async readString(pos) {
- const self = this;
-
- let currentPosition = typeof pos == "undefined" ? self.pos : pos;
-
- if (currentPosition > this.totalSize) {
- if (this.readOnly) {
- throw new Error("Reading out of bounds");
- }
- this._resizeIfNeeded(pos);
- }
- const dataArray = new Uint8Array(
- self.o.data.buffer,
- currentPosition,
- this.totalSize - currentPosition
- );
-
- let indexEndOfString = dataArray.findIndex(element => element === 0);
- let endOfStringFound = indexEndOfString !== -1;
-
- let str = "";
- if (endOfStringFound) {
- str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString));
- self.pos = currentPosition + indexEndOfString + 1;
- } else {
- self.pos = currentPosition;
- }
- return str;
- }
-}
-
-const PAGE_SIZE = 1<<22;
-
-function createNew(o) {
- const initialSize = o.initialSize || 0;
- const fd = new BigMemFile();
- fd.o = o;
- const nPages = initialSize ? Math.floor((initialSize - 1) / PAGE_SIZE)+1 : 0;
- fd.o.data = [];
- for (let i=0; i0) {
- const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r;
- const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l);
- const dstView = new Uint8Array(self.o.data[p].buffer, o, l);
- dstView.set(srcView);
- r = r-l;
- p ++;
- o = 0;
- }
-
- this.pos = pos + buff.byteLength;
- }
-
- async readToBuffer(buffDst, offset, len, pos) {
- const self = this;
- if (typeof pos == "undefined") pos = self.pos;
- if (this.readOnly) {
- if (pos + len > this.totalSize) throw new Error("Reading out of bounds");
- }
- this._resizeIfNeeded(pos + len);
-
- const firstPage = Math.floor(pos / PAGE_SIZE);
-
- let p = firstPage;
- let o = pos % PAGE_SIZE;
- // Remaining bytes to read
- let r = len;
- while (r>0) {
- // bytes to copy from this page
- const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r;
- const srcView = new Uint8Array(self.o.data[p].buffer, o, l);
- buffDst.set(srcView, offset+len-r);
- r = r-l;
- p ++;
- o = 0;
- }
-
- this.pos = pos + len;
- }
-
- async read(len, pos) {
- const self = this;
- const buff = new Uint8Array(len);
-
- await self.readToBuffer(buff, 0, len, pos);
-
- return buff;
- }
-
- close() {
- }
-
- async discard() {
- }
-
-
- async writeULE32(v, pos) {
- const self = this;
-
- tmpBuff32v.setUint32(0, v, true);
-
- await self.write(tmpBuff32, pos);
- }
-
- async writeUBE32(v, pos) {
- const self = this;
-
- tmpBuff32v.setUint32(0, v, false);
-
- await self.write(tmpBuff32, pos);
- }
-
-
- async writeULE64(v, pos) {
- const self = this;
-
- tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true);
- tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true);
-
- await self.write(tmpBuff64, pos);
- }
-
-
- async readULE32(pos) {
- const self = this;
- const b = await self.read(4, pos);
-
- const view = new Uint32Array(b.buffer);
-
- return view[0];
- }
-
- async readUBE32(pos) {
- const self = this;
- const b = await self.read(4, pos);
-
- const view = new DataView(b.buffer);
-
- return view.getUint32(0, false);
- }
-
- async readULE64(pos) {
- const self = this;
- const b = await self.read(8, pos);
-
- const view = new Uint32Array(b.buffer);
-
- return view[1] * 0x100000000 + view[0];
- }
-
- async readString(pos) {
- const self = this;
- const fixedSize = 2048;
-
- let currentPosition = typeof pos == "undefined" ? self.pos : pos;
-
- if (currentPosition > this.totalSize) {
- if (this.readOnly) {
- throw new Error("Reading out of bounds");
- }
- this._resizeIfNeeded(pos);
- }
-
- let endOfStringFound = false;
- let str = "";
-
- while (!endOfStringFound) {
- let currentPage = Math.floor(currentPosition / PAGE_SIZE);
- let offsetOnPage = currentPosition % PAGE_SIZE;
-
- if (self.o.data[currentPage] === undefined) {
- throw new Error("ERROR");
- }
-
- let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage);
- const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength);
-
- let indexEndOfString = dataArray.findIndex(element => element === 0);
- endOfStringFound = indexEndOfString !== -1;
-
- if (endOfStringFound) {
- str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString));
- self.pos = currentPage * PAGE_SIZE + offsetOnPage + indexEndOfString + 1;
- } else {
- str += new TextDecoder().decode(dataArray);
- self.pos = currentPage * PAGE_SIZE + offsetOnPage + dataArray.length;
- }
-
- currentPosition = self.pos;
- }
- return str;
- }
-}
-
-const DEFAULT_CACHE_SIZE = (1 << 16);
-const DEFAULT_PAGE_SIZE = (1 << 13);
-
-
-async function createOverride(o, b, c) {
- if (typeof o === "string") {
- o = {
- type: "file",
- fileName: o,
- cacheSize: b || DEFAULT_CACHE_SIZE,
- pageSize: c || DEFAULT_PAGE_SIZE
- };
- }
- if (o.type == "file") {
- return await open(o.fileName, constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR, o.cacheSize, o.pageSize);
- } else if (o.type == "mem") {
- return createNew$1(o);
- } else if (o.type == "bigMem") {
- return createNew(o);
- } else {
- throw new Error("Invalid FastFile type: " + o.type);
- }
-}
-
-function createNoOverride(o, b, c) {
- if (typeof o === "string") {
- o = {
- type: "file",
- fileName: o,
- cacheSize: b || DEFAULT_CACHE_SIZE,
- pageSize: c || DEFAULT_PAGE_SIZE
- };
- }
- if (o.type == "file") {
- return open(o.fileName, constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL, o.cacheSize, o.pageSize);
- } else if (o.type == "mem") {
- return createNew$1(o);
- } else if (o.type == "bigMem") {
- return createNew(o);
- } else {
- throw new Error("Invalid FastFile type: " + o.type);
- }
-}
-
-async function readExisting(o, b, c) {
- if (o instanceof Uint8Array) {
- o = {
- type: "mem",
- data: o
- };
- }
- if (process.browser) {
- if (typeof o === "string") {
- const buff = await fetch(o).then(function (res) {
- return res.arrayBuffer();
- }).then(function (ab) {
- return new Uint8Array(ab);
- });
- o = {
- type: "mem",
- data: buff
- };
- }
- } else {
- if (typeof o === "string") {
- o = {
- type: "file",
- fileName: o,
- cacheSize: b || DEFAULT_CACHE_SIZE,
- pageSize: c || DEFAULT_PAGE_SIZE
- };
- }
- }
- if (o.type == "file") {
- return await open(o.fileName, constants.O_RDONLY, o.cacheSize, o.pageSize);
- } else if (o.type == "mem") {
- return await readExisting$2(o);
- } else if (o.type == "bigMem") {
- return await readExisting$1(o);
- } else {
- throw new Error("Invalid FastFile type: " + o.type);
- }
-}
-
-function readWriteExisting(o, b, c) {
- if (typeof o === "string") {
- o = {
- type: "file",
- fileName: o,
- cacheSize: b || DEFAULT_CACHE_SIZE,
- pageSize: c || DEFAULT_PAGE_SIZE
- };
- }
- if (o.type == "file") {
- return open(o.fileName, constants.O_CREAT | constants.O_RDWR, o.cacheSize, o.pageSize);
- } else if (o.type == "mem") {
- return readWriteExisting$2(o);
- } else if (o.type == "bigMem") {
- return readWriteExisting$1(o);
- } else {
- throw new Error("Invalid FastFile type: " + o.type);
- }
-}
-
-function readWriteExistingOrCreate(o, b, c) {
- if (typeof o === "string") {
- o = {
- type: "file",
- fileName: o,
- cacheSize: b || DEFAULT_CACHE_SIZE,
- pageSize: c || DEFAULT_PAGE_SIZE
- };
- }
- if (o.type == "file") {
- return open(o.fileName, constants.O_CREAT | constants.O_RDWR | constants.O_EXCL, o.cacheSize);
- } else if (o.type == "mem") {
- return readWriteExisting$2(o);
- } else if (o.type == "bigMem") {
- return readWriteExisting$1(o);
- } else {
- throw new Error("Invalid FastFile type: " + o.type);
- }
-}
-
-exports.createNoOverride = createNoOverride;
-exports.createOverride = createOverride;
-exports.readExisting = readExisting;
-exports.readWriteExisting = readWriteExisting;
-exports.readWriteExistingOrCreate = readWriteExistingOrCreate;
diff --git a/build/node/main.cjs b/build/node/main.cjs
new file mode 100644
index 0000000..22b2962
--- /dev/null
+++ b/build/node/main.cjs
@@ -0,0 +1 @@
+Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("fs");c=s(c,1);let l=require("constants");async function u(e,t,n,r){if(n||=4096*64,typeof t!=`number`&&[`w+`,`wx+`,`r`,`ax+`,`a+`].indexOf(t)<0)throw Error(`Invalid open option`);let i=await c.default.promises.open(e,t);return new d(i,await i.stat(),n,r,e)}var d=class{constructor(e,t,n,r,i){for(this.fileName=i,this.fd=e,this.pos=0,this.pageSize=r||256;this.pageSize{t.pendingLoads.push({page:e,resolve:n,reject:r})});return t.__statusPage(`After Load request: `,e),n}__statusPage(e,t){let n=[],r=this;if(!r.logHistory)return;n.push(`==`+e+` `+t);let i=``;for(let e=0;e `+t.history[e][n][r])}_triggerLoad(){let e=this;if(e.reading||e.pendingLoads.length==0)return;let t=Object.keys(e.pages),n=[];for(let r=0;r0&&(e.pages[e.pendingLoads[0].page]!==void 0||r>0||n.length>0);){let t=e.pendingLoads.shift();if(e.pages[t.page]!==void 0){e.pages[t.page].pendingOps++;let r=n.indexOf(t.page);r>=0&&n.splice(r,1),e.pages[t.page].loading?e.pages[t.page].loading.push(t):t.resolve(),e.__statusPage(`After Load (cached): `,t.page)}else{if(r)r--;else{let t=n.shift();e.__statusPage(`Before Unload: `,t),e.avBuffs.unshift(e.pages[t]),delete e.pages[t],e.__statusPage(`After Unload: `,t)}t.page>=e.totalPages?(e.pages[t.page]=a(),t.resolve(),e.__statusPage(`After Load (new): `,t.page)):(e.reading=!0,e.pages[t.page]=a(),e.pages[t.page].loading=[t],i.push(e.fd.read(e.pages[t.page].buff,0,e.pageSize,t.page*e.pageSize).then(n=>{e.pages[t.page].size=n.bytesRead;let r=e.pages[t.page].loading;delete e.pages[t.page].loading;for(let e=0;e{let r=e.pages[t.page],i=r&&r.loading?r.loading:[t];delete e.pages[t.page];for(let e=0;e{e.reading=!1,e.pendingLoads.length>0&&setImmediate(e._triggerLoad.bind(e)),e._tryClose()});function a(){if(e.avBuffs.length>0){let t=e.avBuffs.shift();return t.dirty=!1,t.pendingOps=1,t.size=0,t}else return{dirty:!1,buff:new Uint8Array(e.pageSize),pendingOps:1,size:0}}}_triggerWrite(){let e=this;if(e.writing)return;let t=Object.keys(e.pages),n=[];for(let r=0;r{i.writing=!1},t=>{console.log(`ERROR Writing: `+t),i.writing=!1,e.error=t,e._tryClose()})))}e.writing&&Promise.all(n).then(()=>{e.writing=!1,setImmediate(e._triggerWrite.bind(e)),e._tryClose(),e.pendingLoads.length>0&&setImmediate(e._triggerLoad.bind(e))})}_getDirtyPage(){for(let e in this.pages)if(this.pages[e].dirty)return e;return-1}_rangeHasCachedPages(e,t){let n=Math.floor(e/this.pageSize),r=Math.floor((e+t-1)/this.pageSize);for(let e of Object.keys(this.pages)){let t=+e;if(t>=n&&t<=r)return!0}return!1}async write(e,t){if(e.byteLength==0)return;let n=this;if(n.error)throw n.error;if(t===void 0&&(t=n.pos),n.pos=t+e.byteLength,n.totalSize=n.directWriteThreshold&&ArrayBuffer.isView(e)&&!n._rangeHasCachedPages(t,e.byteLength)){let r=0;for(;rn.totalPages&&(n.totalPages=i+1);return}let r=Math.floor(t/n.pageSize),i=Math.floor((t+e.byteLength-1)/n.pageSize),a=[];for(let e=r;e<=i;e++)a.push(n._loadPage(e));n._triggerLoad();let o=r,s=t%n.pageSize,c=e.byteLength;for(;c>0;){await a[o-r];let t=s+c>n.pageSize?n.pageSize-s:c,i=e.slice(e.byteLength-c,e.byteLength-c+t);new Uint8Array(n.pages[o].buff.buffer,s,t).set(i),n.pages[o].dirty=!0,n.pages[o].pendingOps--,n.pages[o].size=Math.max(s+t,n.pages[o].size),o>=n.totalPages&&(n.totalPages=o+1),c-=t,o++,s=0,n.writing||setImmediate(n._triggerWrite.bind(n))}}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}_rangeHasDirtyPages(e,t){let n=Math.floor(e/this.pageSize),r=Math.floor((e+t-1)/this.pageSize);for(let e of Object.keys(this.pages)){let t=+e;if(t>=n&&t<=r){let e=this.pages[t];if(e.dirty||e.writing)return!0}}return!1}async readToBuffer(e,t,n,r){if(n==0)return;let i=this;if(i.error)throw i.error;if(r===void 0&&(r=i.pos),i.pos=r+n,i.pendingClose)throw Error(`Reading a closing file`);if(n>=i.directReadThreshold&&ArrayBuffer.isView(e)&&!i._rangeHasDirtyPages(r,n)){let a=r+n>i.totalSize?i.totalSize-r:n;a<0&&(a=0);let o=0;for(;oi.pageSize*i.maxPagesLoaded*.8){let e=Math.floor(n*1.1);this.maxPagesLoaded=Math.floor(e/i.pageSize)+1}let a=Math.floor(r/i.pageSize),o=Math.floor((r+n-1)/i.pageSize),s=[];for(let e=a;e<=o;e++)s.push(i._loadPage(e));i._triggerLoad();let c=a,l=r%i.pageSize,u=r+n>i.totalSize?n-(r+n-i.totalSize):n,d=0;for(;u>0;){await s[c-a],i.__statusPage(`After Await (read): `,c);let n=l+u>i.pageSize?i.pageSize-l:u,r=new Uint8Array(i.pages[c].buff.buffer,i.pages[c].buff.byteOffset+l,n);e.set(r,t+d),i.pages[c].pendingOps--,i.__statusPage(`After Op done: `,c),u-=n,d+=n,c++,l=0,i.pendingLoads.length>0&&setImmediate(i._triggerLoad.bind(i))}this.pos=r+n}_tryClose(){let e=this;if(e.pendingClose){if(e.error){e.pendingCloseReject(e.error);return}e._getDirtyPage()>=0||e.writing||e.reading||e.pendingLoads.length>0||e.pendingClose()}}close(){let e=this;return e.closePromise||=new Promise((t,n)=>{e.pendingClose=t,e.pendingCloseReject=n,e._tryClose()}).then(()=>{e.fd.close()},t=>{throw e.fd.close(),t}),e.closePromise}async discard(){await this.close(),await c.default.promises.unlink(this.fileName)}async writeULE32(e,t){let n=this,r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,e,!0),await n.write(r,t)}async writeUBE32(e,t){let n=this,r=new Uint8Array(4);new DataView(r.buffer).setUint32(0,e,!1),await n.write(r,t)}async writeULE64(e,t){let n=this,r=new Uint8Array(8),i=new DataView(r.buffer);i.setUint32(0,e&4294967295,!0),i.setUint32(4,Math.floor(e/4294967296),!0),await n.write(r,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this;if(t.pendingClose)throw Error(`Reading a closing file`);let n=e===void 0?t.pos:e,r=Math.floor(n/t.pageSize),i=!1,a=``;for(;!i;){let e=t._loadPage(r);t._triggerLoad(),await e,t.__statusPage(`After Await (read): `,r);let o=n%t.pageSize,s=new Uint8Array(t.pages[r].buff.buffer,t.pages[r].buff.byteOffset+o,t.pageSize-o),c=s.findIndex(e=>e===0);i=c!==-1,i?(a+=new TextDecoder().decode(s.slice(0,c)),t.pos=r*this.pageSize+o+c+1):(a+=new TextDecoder().decode(s),t.pos=r*this.pageSize+o+s.length),t.pages[r].pendingOps--,t.__statusPage(`After Op done: `,r),n=t.pos,r++,t.pendingLoads.length>0&&setImmediate(t._triggerLoad.bind(t))}return a}};function f(e){let t=e.initialSize||1<<20,n=new y;return n.o=e,n.o.data=new Uint8Array(t),n.allocSize=t,n.totalSize=0,n.readOnly=!1,n.pos=0,n}function p(e){let t=new y;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!0,t.pos=0,t}function m(e){let t=new y;return t.o=e,t.allocSize=e.data.byteLength,t.totalSize=e.data.byteLength,t.readOnly=!1,t.pos=0,t}var h=new Uint8Array(4),g=new DataView(h.buffer),_=new Uint8Array(8),v=new DataView(_.buffer),y=class{constructor(){this.pageSize=16384}_resizeIfNeeded(e){if(e>this.allocSize){let t=Math.max(this.allocSize+(1<<20),Math.floor(this.allocSize*1.1),e),n=new Uint8Array(t);n.set(this.o.data),this.o.data=n,this.allocSize=t}}async write(e,t){let n=this;if(t===void 0&&(t=n.pos),this.readOnly)throw Error(`Writing a read only file`);this._resizeIfNeeded(t+e.byteLength),this.o.data.set(e.slice(),t),t+e.byteLength>this.totalSize&&(this.totalSize=t+e.byteLength),this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=new Uint8Array(this.o.data.buffer,this.o.data.byteOffset+r,n);e.set(a,t),this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){this.o.data.byteLength!=this.totalSize&&(this.o.data=this.o.data.slice(0,this.totalSize))}async discard(){}async writeULE32(e,t){let n=this;g.setUint32(0,e,!0),await n.write(h,t)}async writeUBE32(e,t){let n=this;g.setUint32(0,e,!1),await n.write(h,t)}async writeULE64(e,t){let n=this;v.setUint32(0,e&4294967295,!0),v.setUint32(4,Math.floor(e/4294967296),!0),await n.write(_,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>=this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);return``}let r=new Uint8Array(t.o.data.buffer,n,this.totalSize-n),i=r.findIndex(e=>e===0),a=i!==-1,o=``;return a?(o=new TextDecoder().decode(r.slice(0,i)),t.pos=n+i+1):t.pos=n,o}},b=1<<22;function x(e){let t=e.initialSize||0,n=new D;n.o=e;let r=t?Math.floor((t-1)/b)+1:0;n.o.data=[];for(let e=0;e0;){let t=i+a>b?b-i:a,o=e.slice(e.byteLength-a,e.byteLength-a+t);new Uint8Array(n.o.data[r].buffer,i,t).set(o),a-=t,r++,i=0}this.pos=t+e.byteLength}async readToBuffer(e,t,n,r){let i=this;if(r===void 0&&(r=i.pos),this.readOnly&&r+n>this.totalSize)throw Error(`Reading out of bounds`);this._resizeIfNeeded(r+n);let a=Math.floor(r/b),o=r%b,s=n;for(;s>0;){let r=o+s>b?b-o:s,c=new Uint8Array(i.o.data[a].buffer,o,r);e.set(c,t+n-s),s-=r,a++,o=0}this.pos=r+n}async read(e,t){let n=this,r=new Uint8Array(e);return await n.readToBuffer(r,0,e,t),r}close(){}async discard(){}async writeULE32(e,t){let n=this;w.setUint32(0,e,!0),await n.write(C,t)}async writeUBE32(e,t){let n=this;w.setUint32(0,e,!1),await n.write(C,t)}async writeULE64(e,t){let n=this;E.setUint32(0,e&4294967295,!0),E.setUint32(4,Math.floor(e/4294967296),!0),await n.write(T,t)}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this,n=e===void 0?t.pos:e;if(n>this.totalSize){if(this.readOnly)throw Error(`Reading out of bounds`);this._resizeIfNeeded(e)}let r=!1,i=``;for(;!r;){let e=Math.floor(n/b),a=n%b;if(t.o.data[e]===void 0)throw Error(`ERROR`);let o=Math.min(2048,t.o.data[e].length-a);if(o<=0)return t.pos=n,i;let s=new Uint8Array(t.o.data[e].buffer,a,o),c=s.findIndex(e=>e===0);r=c!==-1,r?(i+=new TextDecoder().decode(s.slice(0,c)),t.pos=e*b+a+c+1):(i+=new TextDecoder().decode(s),t.pos=e*b+a+s.length),n=t.pos}return i}},te=1<<20,O=8192,k=class{constructor(e,t,n,r){this.readRangeInto=e,this.totalSize=t,this.pos=0,this.pageSize=r||O,this.maxPagesLoaded=Math.floor((n||te)/this.pageSize)+1,this.pages=new Map,this.readOnly=!0}_pageLen(e){let t=e*this.pageSize;return Math.min(t+this.pageSize,this.totalSize)-t}_loadPage(e){let t=this,n=t.pages.get(e);if(n)return t.pages.delete(e),t.pages.set(e,n),n.promise;let r=new Uint8Array(t._pageLen(e));return n={buff:null,promise:null},n.promise=t.readRangeInto(r,0,e*t.pageSize,r.byteLength).then(function(){return n.buff=r,r},function(n){throw t.pages.delete(e),n}),t.pages.set(e,n),t._trimCache(),n.promise}_trimCache(){let e=this;if(!(e.pages.size<=e.maxPagesLoaded))for(let t of e.pages){if(e.pages.size<=e.maxPagesLoaded)return;t[1].buff&&e.pages.delete(t[0])}}async readToBuffer(e,t,n,r){let i=this;if(n===0)return;if(i.pendingClose)throw Error(`Reading a closing file`);if(r===void 0&&(r=i.pos),r+n>i.totalSize)throw Error(`Reading out of bounds`);if(i.pos=r+n,n>=i.pageSize){await i.readRangeInto(e,t,r,n);return}let a=Math.floor(r/i.pageSize),o=Math.floor((r+n-1)/i.pageSize),s=r%i.pageSize,c=0;for(let r=a;r<=o;r++){let a=await i._loadPage(r),o=Math.min(n-c,i.pageSize-s);e.set(a.subarray(s,s+o),t+c),c+=o,s=0}}async read(e,t){let n=new Uint8Array(e);return await this.readToBuffer(n,0,e,t),n}async readULE32(e){let t=await this.read(4,e);return new Uint32Array(t.buffer)[0]}async readUBE32(e){let t=await this.read(4,e);return new DataView(t.buffer).getUint32(0,!1)}async readULE64(e){let t=await this.read(8,e),n=new Uint32Array(t.buffer);return n[1]*4294967296+n[0]}async readString(e){let t=this;if(t.pendingClose)throw Error(`Reading a closing file`);let n=e===void 0?t.pos:e,r=[];for(;n=0)return r.push(i.subarray(0,a)),t.pos=n+a+1,A(r);r.push(i),n+=e}return t.pos=n,A(r)}async write(){throw Error(`Writing a read only file`)}async writeULE32(){throw Error(`Writing a read only file`)}async writeUBE32(){throw Error(`Writing a read only file`)}async writeULE64(){throw Error(`Writing a read only file`)}async close(){this.pendingClose||(this.pendingClose=!0,this.pages.clear())}async discard(){await this.close()}};function A(e){let t=0;for(let n=0;n{let r=indexedDB.open(e,1);r.onupgradeneeded=()=>{let e=r.result;e.createObjectStore(`files`),e.createObjectStore(`blocks`)},r.onsuccess=()=>t(r.result),r.onerror=()=>n(r.error),r.onblocked=()=>n(Error(`IndexedDB open blocked`))});return P.set(e,t),t.catch(()=>P.delete(e)),t}function I(e){return new Promise((t,n)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>n(e.error)})}function L(e){return new Promise((t,n)=>{e.oncomplete=()=>t(),e.onerror=()=>n(e.error),e.onabort=()=>n(e.error||Error(`IndexedDB transaction aborted`))})}function R(e,t,n){return IDBKeyRange.bound([e,t],[e,n])}async function z(e,t){let n=e.transaction([`files`,`blocks`],`readwrite`);n.objectStore(`files`).delete(t),n.objectStore(`blocks`).delete(R(t,0,1/0)),await L(n)}async function B(e,t,n,r,i,a){let o=e.transaction([`files`,`blocks`],`readwrite`),s=o.objectStore(`files`),c=await I(s.get(t)),l=0;c&&c.validator===n&&c.totalSize===r&&c.blockSize===i?l=c.bytes:c&&o.objectStore(`blocks`).delete(R(t,0,1/0)),s.put({validator:n,totalSize:r,blockSize:i,bytes:l,lastUsed:Date.now()},t),await L(o);let u=e.transaction(`files`,`readonly`),d=u.objectStore(`files`),[f,p]=await Promise.all([I(d.getAllKeys()),I(d.getAll())]);await L(u);let m=p.reduce((e,t)=>e+t.bytes,0);if(m<=a)return;let h=f.map((e,t)=>({key:e,meta:p[t]})).filter(e=>e.key!==t).sort((e,t)=>e.meta.lastUsed-t.meta.lastUsed);for(let t of h){if(m<=a)break;await z(e,t.key),m-=t.meta.bytes}}async function ne(e,t){let{fileKey:n,validator:r,totalSize:i}=t,a=typeof t.options==`object`&&t.options||{},o=a.blockSize||j,s=a.maxBytes||M,c=a.dbName||N;if(typeof indexedDB>`u`||!r)return e;let l;try{l=await F(c),await B(l,n,r,i,o,s)}catch{return e}let u=!1;async function d(e,t){let r=l.transaction(`blocks`,`readonly`),i=r.objectStore(`blocks`),a=R(n,e,t),[o,s]=await Promise.all([I(i.getAllKeys(a)),I(i.getAll(a))]);await L(r);let c=new Map;for(let e=0;ee+t.data.byteLength,0),a.lastUsed=Date.now(),i.put(a,n)),await L(t)}catch{u=!0}}let p=e=>Math.min(o,i-e*o),m=new Map;function h(e){let t,n,r=new Promise((e,r)=>{t=e,n=r});return r.catch(()=>{}),m.set(e,r),{resolve:t,reject:n,promise:r}}return async function(t,n,r,i){if(i===0)return;let a=Math.floor(r/o),s=Math.floor((r+i-1)/o),c=await d(a,s),l=[],u=(e,a)=>{let s=a*o,c=Math.max(r,s),l=Math.min(r+i,s+p(a));t.set(e.subarray(c-s,l-s),n+(c-r))},g=a;for(;g<=s;){let a=g*o,d=a+p(g),f=c.get(g);if(f){u(f,g),g++;continue}let _=m.get(g);if(_){u(await _,g),g++;continue}if(a>=r&&d<=r+i){let u=g;for(;u+1<=s&&!c.get(u+1)&&!m.get(u+1)&&(u+1)*o+p(u+1)<=r+i;)u++;let d=a,f=u*o+p(u),_=[];for(let e=g;e<=u;e++)_.push(h(e));try{await e(t,n+(d-r),d,f-d)}catch(e){for(let t=g;t<=u;t++)_[t-g].reject(e),m.delete(t);throw e}for(let e=g;e<=u;e++){let i=e*o,a=t.slice(n+(i-r),n+(i-r)+p(e));_[e-g].resolve(a),l.push({index:e,data:a})}g=u+1}else{let t=h(g),n=new Uint8Array(p(g));try{await e(n,0,a,n.length)}catch(e){throw t.reject(e),m.delete(g),e}t.resolve(n),u(n,g),l.push({index:g,data:n}),g++}}await f(l);for(let e of l)m.delete(e.index)}}async function re(e){let t=(typeof e.options==`object`&&e.options||{}).dbName||N;if(typeof indexedDB>`u`)return null;try{let n=(await F(t)).transaction(`files`,`readonly`),r=await I(n.objectStore(`files`).get(e.fileKey));return await L(n),r?{validator:r.validator,totalSize:r.totalSize,blockSize:r.blockSize,bytes:r.bytes}:null}catch{return null}}async function ie(e){let{fileKey:t,validator:n,totalSize:r,data:i}=e,a=typeof e.options==`object`&&e.options||{},o=a.blockSize||j,s=a.maxBytes||M,c=a.dbName||N;if(typeof indexedDB>`u`||!n)return!1;try{let e=await F(c);await B(e,t,n,r,o,s);let a=Math.ceil(r/o);for(let n=0;ns.byteLength)throw Error(e+`: read past the end of the buffered body`);n.set(s.subarray(a,a+o),r)},o=Math.min(r.pageSize||V,V);return r.cache&&(a=await ne(a,{fileKey:e,validator:t,totalSize:n,options:r.cache})),new k(a,n,r.cacheSize,o)}async function W(e){let t=await fetch(e);if(!t.ok)throw Error(`HTTP `+t.status+` fetching `+e);return p({type:`mem`,data:new Uint8Array(await t.arrayBuffer())})}function G(e){let t=e.headers.get(`etag`);return t&&t.indexOf(`W/`)!==0?t:e.headers.get(`last-modified`)||null}var ae=4,K=0,q=[];async function oe(e){for(;K>=ae;)await new Promise(e=>q.push(e));K++;try{return await e()}finally{K--;let e=q.shift();e&&e()}}var J={retries:3,backoffMs:300,stallTimeoutMs:1e4},se=e=>new Promise(t=>setTimeout(t,e));async function ce(e,t,n,r,i,a){return oe(async()=>{for(let o=0;;o++)try{return await le(e,t,n,r,i,a)}catch(e){if(e&&(e.degradeToFull||e.permanent)||o>=J.retries)throw e;await se(J.backoffMs*(1<{s&&(c&&clearTimeout(c),c=setTimeout(()=>s.abort(Error(e+`: no data for `+J.stallTimeoutMs+`ms`)),J.stallTimeoutMs))},u=()=>{c&&clearTimeout(c),c=null};l();let d;try{d=await fetch(e,s?{headers:o,signal:s.signal}:{headers:o})}catch(e){throw u(),e}if(l(),d.status===200){let n=G(d);if(!t||n&&n===t){u();let t=Error(e+`: origin ignored Range; degrading to full buffering`);throw t.degradeToFull=!0,t.fullBodyPromise=d.arrayBuffer().then(e=>new Uint8Array(e)),t}u(),await Y(d);let r=Error(e+`: file changed (or server stopped honoring Range) while reading`);throw r.permanent=!0,r}if(d.status!==206){u(),await Y(d);let t=Error(`HTTP `+d.status+` reading range `+i+`+`+a+` of `+e);throw d.status<500&&d.status!==429&&(t.permanent=!0),t}let f=d.headers.get(`content-range`),p=f?/bytes\s+(\d+)-(\d+)\//.exec(f):null;if(p&&parseInt(p[1])!==i)throw await Y(d),Error(e+`: server returned range starting at `+p[1]+`, requested `+i);let m=0;try{if(d.body&&typeof d.body.getReader==`function`){let t=d.body.getReader();for(;;){let i=await t.read();if(l(),i.done)break;if(m+i.value.byteLength>a)throw t.cancel().catch(function(){}),Error(e+`: range response longer than requested`);n.set(i.value,r+m),m+=i.value.byteLength}}else{let t=new Uint8Array(await d.arrayBuffer());if(t.byteLength>a)throw Error(e+`: range response longer than requested`);n.set(t,r),m=t.byteLength}}finally{u()}if(m!==a)throw Error(e+`: short range response (`+m+`/`+a+` bytes at `+i+`)`)}async function Y(e){try{e.body&&typeof e.body.cancel==`function`?await e.body.cancel():await e.arrayBuffer()}catch{}}var X=1<<20;function ue(e){let t=e.blob,n=async function(e,n,r,i){let a=await t.slice(r,r+i).arrayBuffer();if(a.byteLength!==i)throw Error(`short blob read (`+a.byteLength+`/`+i+` bytes at `+r+`)`);e.set(new Uint8Array(a),n)},r=Math.min(e.pageSize||X,X);return new k(n,t.size,e.cacheSize,r)}var Z=65536,Q=8192,de=typeof process<`u`&&process.versions!=null&&process.versions.node!=null;function $(e,t,n){if(typeof e!=`object`||!e||e.type!==`file`&&e.type!==`http`&&e.type!==`blob`)return e;let r=e.cacheSize===void 0&&t!==void 0,i=e.pageSize===void 0&&n!==void 0;if(!r&&!i)return e;let a=Object.assign({},e);return r&&(a.cacheSize=t),i&&(a.pageSize=n),a}async function fe(e,t,n){if(typeof e==`string`&&(e={type:`file`,fileName:e,cacheSize:t||Z,pageSize:n||Q}),e=$(e,t,n),e.type==`file`)return await u(e.fileName,l.O_TRUNC|l.O_CREAT|l.O_RDWR,e.cacheSize,e.pageSize);if(e.type==`mem`)return f(e);if(e.type==`bigMem`)return x(e);throw Error(`Invalid FastFile type: `+e.type)}function pe(e,t,n){if(typeof e==`string`&&(e={type:`file`,fileName:e,cacheSize:t||Z,pageSize:n||Q}),e=$(e,t,n),e.type==`file`)return u(e.fileName,l.O_TRUNC|l.O_CREAT|l.O_RDWR|l.O_EXCL,e.cacheSize,e.pageSize);if(e.type==`mem`)return f(e);if(e.type==`bigMem`)return x(e);throw Error(`Invalid FastFile type: `+e.type)}async function me(e,t,n){if(e instanceof Uint8Array&&(e={type:`mem`,data:e}),typeof Blob<`u`&&e instanceof Blob&&(e={type:`blob`,blob:e,cacheSize:t,pageSize:n}),typeof e==`string`&&(e=!de||/^https?:\/\//i.test(e)?{type:`http`,url:e,cacheSize:t,pageSize:n}:{type:`file`,fileName:e,cacheSize:t||Z,pageSize:n||Q}),e=$(e,t,n),e.type==`file`)return await u(e.fileName,l.O_RDONLY,e.cacheSize,e.pageSize);if(e.type==`mem`)return await p(e);if(e.type==`bigMem`)return await ee(e);if(e.type==`http`)return await H(e);if(e.type==`blob`)return ue(e);throw Error(`Invalid FastFile type: `+e.type)}function he(e,t,n){if(typeof e==`string`&&(e={type:`file`,fileName:e,cacheSize:t||Z,pageSize:n||Q}),e=$(e,t,n),e.type==`file`)return u(e.fileName,l.O_CREAT|l.O_RDWR,e.cacheSize,e.pageSize);if(e.type==`mem`)return m(e);if(e.type==`bigMem`)return S(e);throw Error(`Invalid FastFile type: `+e.type)}function ge(e,t,n){if(typeof e==`string`&&(e={type:`file`,fileName:e,cacheSize:t||Z,pageSize:n||Q}),e=$(e,t,n),e.type==`file`)return u(e.fileName,l.O_CREAT|l.O_RDWR|l.O_EXCL,e.cacheSize);if(e.type==`mem`)return m(e);if(e.type==`bigMem`)return S(e);throw Error(`Invalid FastFile type: `+e.type)}exports.createNoOverride=pe,exports.createOverride=fe,exports.readExisting=me,exports.readWriteExisting=he,exports.readWriteExistingOrCreate=ge;
\ No newline at end of file
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..db65781
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,33 @@
+import js from "@eslint/js";
+import globals from "globals";
+
+export default [
+ { ignores: ["build/**", "node_modules/**"] },
+ js.configs.recommended,
+ {
+ languageOptions: {
+ ecmaVersion: 2022,
+ sourceType: "module",
+ globals: {
+ ...globals.node,
+ ...globals.browser,
+ },
+ },
+ rules: {
+ "no-unused-vars": ["error", { caughtErrors: "none" }],
+ "indent": ["error", 4],
+ "linebreak-style": ["warn", "unix"],
+ "quotes": ["error", "double"],
+ "semi": ["error", "always"],
+ },
+ },
+ {
+ // Vitest globals for test files (describe, it, beforeEach, etc.)
+ files: ["test/**/*.js"],
+ languageOptions: {
+ globals: {
+ ...globals.mocha,
+ },
+ },
+ },
+];
diff --git a/package-lock.json b/package-lock.json
index a475cd1..b63021f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,528 +9,941 @@
"version": "0.0.20",
"license": "GPL-3.0",
"devDependencies": {
- "chai": "^4.3.6",
- "chai-as-promised": "^7.1.1",
- "eslint": "^8.17.0",
- "ffjavascript": "^0.3.0",
- "mocha": "^10.0.0",
- "rollup": "^2.20.0"
+ "@eslint/js": "^10.0.1",
+ "@vitest/browser": "^4.1.11",
+ "@vitest/browser-playwright": "^4.1.11",
+ "eslint": "^10.1.0",
+ "ffjavascript": "git+https://github.com/iden3/ffjavascript.git#cc88563e1686646616ad0fcfafa6cb09c879dd25",
+ "globals": "^17.4.0",
+ "playwright": "^1.59.0",
+ "vite": "^8.0.3",
+ "vitest": "^4.1.11"
+ }
+ },
+ "node_modules/@blazediff/core": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz",
+ "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
+ "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.2",
+ "tslib": "^2.4.0"
}
},
- "node_modules/@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "node_modules/@emnapi/runtime": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
+ "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
"dev": true,
- "engines": {
- "node": ">=0.10.0"
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
- "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "eslint-visitor-keys": "^3.3.0"
+ "eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@eslint-community/regexpp": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz",
- "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==",
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
- "node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "node_modules/@eslint/config-array": {
+ "version": "0.23.5",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz",
+ "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
+ "@eslint/object-schema": "^3.0.5",
+ "debug": "^4.3.1",
+ "minimatch": "^10.2.4"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
- "node_modules/@eslint/js": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
- "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz",
+ "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==",
"dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^1.2.1"
+ },
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.13",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
- "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
+ "node_modules/@eslint/core": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
+ "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
+ "@types/json-schema": "^7.0.15"
},
"engines": {
- "node": ">=10.10.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "node_modules/@eslint/js": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
+ "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=12.22"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "eslint": "^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
}
},
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
- "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
- "dev": true
+ "node_modules/@eslint/object-schema": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
+ "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
},
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz",
+ "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
+ "@eslint/core": "^1.2.1",
+ "levn": "^0.4.1"
},
"engines": {
- "node": ">= 8"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "node_modules/@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
"dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
"engines": {
- "node": ">= 8"
+ "node": ">=18.18.0"
}
},
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "node_modules/@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
},
"engines": {
- "node": ">= 8"
+ "node": ">=18.18.0"
}
},
- "node_modules/@ungap/structured-clone": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
- "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
- "dev": true
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
},
- "node_modules/acorn": {
- "version": "8.11.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
- "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
- "peer": true,
- "bin": {
- "acorn": "bin/acorn"
- },
+ "license": "Apache-2.0",
"engines": {
- "node": ">=0.4.0"
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
+ "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
+ "@tybys/wasm-util": "^0.10.3"
},
"funding": {
"type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "peerDependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1"
}
},
- "node_modules/ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "node_modules/@oxc-project/types": {
+ "version": "0.137.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz",
+ "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==",
"dev": true,
- "engines": {
- "node": ">=6"
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
}
},
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.29",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rolldown/binding-android-arm64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz",
+ "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
"engines": {
- "node": ">=8"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "node_modules/@rolldown/binding-darwin-arm64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz",
+ "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "node_modules/@rolldown/binding-darwin-x64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz",
+ "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">= 8"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/assertion-error": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
- "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "node_modules/@rolldown/binding-freebsd-x64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz",
+ "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
"engines": {
- "node": "*"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true
- },
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz",
+ "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==",
+ "cpu": [
+ "arm"
+ ],
"dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=8"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "node_modules/@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz",
+ "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "node_modules/@rolldown/binding-linux-arm64-musl": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz",
+ "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "fill-range": "^7.1.1"
- },
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=8"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/browser-stdout": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
- "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
- "dev": true
+ "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz",
+ "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
},
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "node_modules/@rolldown/binding-linux-s390x-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz",
+ "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==",
+ "cpu": [
+ "s390x"
+ ],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=6"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "node_modules/@rolldown/binding-linux-x64-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz",
+ "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/chai": {
- "version": "4.3.10",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
- "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
+ "node_modules/@rolldown/binding-linux-x64-musl": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz",
+ "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "peer": true,
- "dependencies": {
- "assertion-error": "^1.1.0",
- "check-error": "^1.0.3",
- "deep-eql": "^4.1.3",
- "get-func-name": "^2.0.2",
- "loupe": "^2.3.6",
- "pathval": "^1.1.1",
- "type-detect": "^4.0.8"
- },
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=4"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/chai-as-promised": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
- "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
+ "node_modules/@rolldown/binding-openharmony-arm64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz",
+ "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "check-error": "^1.0.2"
- },
- "peerDependencies": {
- "chai": ">= 2.1.2 < 5"
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "node_modules/@rolldown/binding-wasm32-wasi": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz",
+ "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==",
+ "cpu": [
+ "wasm32"
+ ],
"dev": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
+ "@emnapi/core": "1.11.1",
+ "@emnapi/runtime": "1.11.1",
+ "@napi-rs/wasm-runtime": "^1.1.6"
},
"engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/check-error": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
- "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
+ "node_modules/@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz",
+ "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "get-func-name": "^2.0.2"
- },
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
"engines": {
- "node": "*"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "node_modules/@rolldown/binding-win32-x64-msvc": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz",
+ "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
],
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
"engines": {
- "node": ">= 8.10.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
+ "node": "^20.19.0 || >=22.12.0"
}
},
- "node_modules/cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
+ "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
"dev": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
+ "tslib": "^2.4.0"
}
},
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "node_modules/@types/chai": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+ "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
+ "@types/deep-eql": "*",
+ "assertion-error": "^2.0.1"
}
},
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "node_modules/@types/deep-eql": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true
+ "node_modules/@types/esrecurse": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+ "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vitest/browser": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.11.tgz",
+ "integrity": "sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
+ "@blazediff/core": "1.9.1",
+ "@vitest/mocker": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "magic-string": "^0.30.21",
+ "pngjs": "^7.0.0",
+ "sirv": "^3.0.2",
+ "tinyrainbow": "^3.1.0",
+ "ws": "^8.19.0"
},
- "engines": {
- "node": ">= 8"
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "vitest": "4.1.11"
}
},
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "node_modules/@vitest/browser-playwright": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.11.tgz",
+ "integrity": "sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "ms": "2.1.2"
+ "@vitest/browser": "4.1.11",
+ "@vitest/mocker": "4.1.11",
+ "tinyrainbow": "^3.1.0"
},
- "engines": {
- "node": ">=6.0"
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "playwright": "*",
+ "vitest": "4.1.11"
},
"peerDependenciesMeta": {
- "supports-color": {
+ "playwright": {
+ "optional": false
+ }
+ }
+ },
+ "node_modules/@vitest/expect": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
+ "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.1.0",
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "chai": "^6.2.2",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/mocker": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
+ "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "4.1.11",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
"optional": true
}
}
},
- "node_modules/decamelize": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
- "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "node_modules/@vitest/pretty-format": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
+ "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
+ "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "4.1.11",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
+ "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "magic-string": "^0.30.21",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
+ "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
+ "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "4.1.11",
+ "convert-source-map": "^2.0.0",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
+ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
"dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
"engines": {
- "node": ">=10"
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "type-detect": "^4.0.0"
+ "balanced-match": "^4.0.2"
},
"engines": {
- "node": ">=6"
+ "node": "20 || >=22"
}
},
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
+ "node_modules/chai": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+ "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
},
- "node_modules/diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
"engines": {
- "node": ">=0.3.1"
+ "node": ">= 8"
}
},
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "esutils": "^2.0.2"
+ "ms": "^2.1.3"
},
"engines": {
- "node": ">=6.0.0"
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
- "node": ">=6"
+ "node": ">=8"
}
},
+ "node_modules/es-module-lexer": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz",
+ "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -544,84 +957,91 @@
}
},
"node_modules/eslint": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
- "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.6.0.tgz",
+ "integrity": "sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==",
"dev": true,
- "peer": true,
+ "license": "MIT",
+ "workspaces": [
+ "packages/*"
+ ],
"dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.56.0",
- "@humanwhocodes/config-array": "^0.11.13",
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@eslint/config-array": "^0.23.5",
+ "@eslint/config-helpers": "^0.6.0",
+ "@eslint/core": "^1.2.1",
+ "@eslint/plugin-kit": "^0.7.2",
+ "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "cross-spawn": "^7.0.6",
"debug": "^4.3.2",
- "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
+ "eslint-scope": "^9.1.2",
+ "eslint-visitor-keys": "^5.0.1",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
+ "file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
+ "minimatch": "^10.2.4",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
+ "optionator": "^0.9.3"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
}
},
"node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+ "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
+ "@types/esrecurse": "^4.3.1",
+ "@types/estree": "^1.0.8",
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -632,6 +1052,7 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
@@ -640,27 +1061,29 @@
}
},
"node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.9.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "eslint-visitor-keys": "^5.0.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/esquery": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
- "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"estraverse": "^5.1.0"
},
@@ -673,6 +1096,7 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -685,79 +1109,87 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
},
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/expect-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
+ "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
"dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
+ "license": "MIT"
},
"node_modules/ffjavascript": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.0.tgz",
- "integrity": "sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==",
+ "version": "0.3.1",
+ "resolved": "git+https://github.com/iden3/ffjavascript.git#cc88563e1686646616ad0fcfafa6cb09c879dd25",
+ "integrity": "sha512-CLLd+R83k5OOIj14sPLlxlLX8YwuOFUn51Rt3XwQIegHbQyga5fMZ8DO/uCx/jVZzm1NEqSaevmQO7VNW8KVtA==",
"dev": true,
+ "license": "GPL-3.0",
"dependencies": {
+ "web-worker": "1.5.0"
+ },
+ "optionalDependencies": {
"wasmbuilder": "0.0.16",
- "wasmcurves": "0.2.2",
- "web-worker": "1.2.0"
+ "wasmcurves": "git+https://github.com/iden3/wasmcurves.git#13d4acc125b794a4e28a5dc1ea99f015d863ec98"
}
},
"node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "to-regex-range": "^5.0.1"
+ "flat-cache": "^4.0.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=16.0.0"
}
},
"node_modules/find-up": {
@@ -776,39 +1208,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/flat": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
- "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
- "dev": true,
- "bin": {
- "flat": "cli.js"
- }
- },
"node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16"
}
},
"node_modules/flatted": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz",
- "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==",
- "dev": true
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/fsevents": {
"version": "2.3.2",
@@ -824,273 +1243,383 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "node_modules/globals": {
+ "version": "17.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz",
+ "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": "6.* || 8.* || >= 10.*"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/get-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": "*"
+ "node": ">= 4"
}
},
- "node_modules/glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
+ "license": "MIT",
"engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "node": ">=0.8.19"
}
},
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
"engines": {
- "node": ">= 6"
+ "node": ">=0.10.0"
}
},
- "node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"dependencies": {
- "type-fest": "^0.20.2"
+ "is-extglob": "^2.1.1"
},
"engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=0.10.0"
}
},
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
},
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true,
- "engines": {
- "node": ">=8"
- }
+ "license": "MIT"
},
- "node_modules/he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
- "bin": {
- "he": "bin/he"
- }
+ "license": "MIT"
},
- "node_modules/ignore": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
- "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true,
- "engines": {
- "node": ">= 4"
- }
+ "license": "MIT"
},
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "json-buffer": "3.0.1"
}
},
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
"engines": {
- "node": ">=0.8.19"
+ "node": ">= 0.8.0"
}
},
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
"dev": true,
+ "license": "MPL-2.0",
"dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=8"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
"engines": {
- "node": ">=8"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
"dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=0.12.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=8"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=8"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=10"
+ "node": ">= 12.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
},
- "bin": {
- "js-yaml": "bin/js-yaml.js"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/js-yaml/node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
- "dev": true
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
"engines": {
- "node": ">= 0.8.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
"node_modules/locate-path": {
@@ -1108,42 +1637,22 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dev": true,
- "dependencies": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/loupe": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
- "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "get-func-name": "^2.0.0"
+ "@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -1151,99 +1660,35 @@
"node": "*"
}
},
- "node_modules/mocha": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
- "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.4",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "7.2.0",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "5.0.1",
- "ms": "2.1.3",
- "nanoid": "3.3.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "workerpool": "6.2.1",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
- },
- "bin": {
- "_mocha": "bin/_mocha",
- "mocha": "bin/mocha.js"
- },
- "engines": {
- "node": ">= 14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mochajs"
- }
- },
- "node_modules/mocha/node_modules/brace-expansion": {
+ "node_modules/mrmime": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
"dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/mocha/node_modules/minimatch": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
- "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
+ "license": "MIT",
"engines": {
"node": ">=10"
}
},
- "node_modules/mocha/node_modules/ms": {
+ "node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
- "node_modules/mocha/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
+ "license": "MIT"
},
"node_modules/nanoid": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
- "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
"dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -1254,39 +1699,37 @@
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
- "dev": true
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
+ "license": "MIT"
},
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "node_modules/obug": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz",
+ "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==",
"dev": true,
- "dependencies": {
- "wrappy": "1"
+ "funding": [
+ "https://github.com/sponsors/sxzz",
+ "https://opencollective.com/debug"
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
}
},
"node_modules/optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
@@ -1331,18 +1774,6 @@
"node": ">=6"
}
},
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -1352,212 +1783,166 @@
"node": ">=8"
}
},
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
- "node_modules/pathval": {
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
- "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
- "engines": {
- "node": "*"
- }
+ "license": "ISC"
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8.6"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "node_modules/playwright": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz",
+ "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==",
"dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.61.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
"engines": {
- "node": ">= 0.8.0"
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
}
},
- "node_modules/punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "node_modules/playwright-core": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz",
+ "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/pngjs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
+ "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=6"
+ "node": ">=14.19.0"
}
},
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "node_modules/postcss": {
+ "version": "8.5.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
+ "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
"dev": true,
"funding": [
{
- "type": "github",
- "url": "https://github.com/sponsors/feross"
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
},
{
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
},
{
- "type": "consulting",
- "url": "https://feross.org/support"
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
}
- ]
- },
- "node_modules/randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "^5.1.0"
- }
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
+ ],
+ "license": "MIT",
"dependencies": {
- "picomatch": "^2.2.1"
+ "nanoid": "^3.3.17",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
},
"engines": {
- "node": ">=8.10.0"
+ "node": "^10 || ^12 || >=14"
}
},
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=4"
+ "node": ">= 0.8.0"
}
},
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true,
+ "license": "MIT",
"engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
+ "node": ">=6"
}
},
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "node_modules/rolldown": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz",
+ "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "glob": "^7.1.3"
+ "@oxc-project/types": "=0.137.0",
+ "@rolldown/pluginutils": "^1.0.0"
},
"bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
- "dev": true,
- "bin": {
- "rollup": "dist/bin/rollup"
+ "rolldown": "bin/cli.mjs"
},
"engines": {
- "node": ">=10.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
- "dev": true,
- "dependencies": {
- "randombytes": "^2.1.0"
+ "@rolldown/binding-android-arm64": "1.1.3",
+ "@rolldown/binding-darwin-arm64": "1.1.3",
+ "@rolldown/binding-darwin-x64": "1.1.3",
+ "@rolldown/binding-freebsd-x64": "1.1.3",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.1.3",
+ "@rolldown/binding-linux-arm64-gnu": "1.1.3",
+ "@rolldown/binding-linux-arm64-musl": "1.1.3",
+ "@rolldown/binding-linux-ppc64-gnu": "1.1.3",
+ "@rolldown/binding-linux-s390x-gnu": "1.1.3",
+ "@rolldown/binding-linux-x64-gnu": "1.1.3",
+ "@rolldown/binding-linux-x64-musl": "1.1.3",
+ "@rolldown/binding-openharmony-arm64": "1.1.3",
+ "@rolldown/binding-wasm32-wasi": "1.1.3",
+ "@rolldown/binding-win32-arm64-msvc": "1.1.3",
+ "@rolldown/binding-win32-x64-msvc": "1.1.3"
}
},
"node_modules/shebang-command": {
@@ -1565,6 +1950,7 @@
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
},
@@ -1577,83 +1963,143 @@
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/sirv": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+ "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=18"
}
},
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
+ "license": "BSD-3-Clause",
"engines": {
- "node": ">=8"
+ "node": ">=0.10.0"
}
},
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/std-env": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz",
+ "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinybench": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyexec": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz",
+ "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=18"
}
},
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "has-flag": "^4.0.0"
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
},
"engines": {
- "node": ">=8"
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
}
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
- "dev": true
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
},
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyrainbow": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz",
+ "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8.0"
+ "node": ">=14.0.0"
}
},
+ "node_modules/totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD",
+ "optional": true
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1"
},
@@ -1661,461 +2107,798 @@
"node": ">= 0.8.0"
}
},
- "node_modules/type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
- "engines": {
- "node": ">=4"
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
}
},
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "node_modules/vite": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz",
+ "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lightningcss": "^1.32.0",
+ "picomatch": "^4.0.4",
+ "postcss": "^8.5.15",
+ "rolldown": "~1.1.2",
+ "tinyglobby": "^0.2.17"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
"engines": {
- "node": ">=10"
+ "node": "^20.19.0 || >=22.12.0"
},
"funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "@vitejs/devtools": "^0.3.0",
+ "esbuild": "^0.27.0 || ^0.28.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "@vitejs/devtools": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
}
},
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "node_modules/vite/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
+ "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/expect": "4.1.11",
+ "@vitest/mocker": "4.1.11",
+ "@vitest/pretty-format": "4.1.11",
+ "@vitest/runner": "4.1.11",
+ "@vitest/snapshot": "4.1.11",
+ "@vitest/spy": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "es-module-lexer": "^2.0.0",
+ "expect-type": "^1.3.0",
+ "magic-string": "^0.30.21",
+ "obug": "^2.1.1",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3",
+ "std-env": "^4.0.0-rc.1",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^1.0.2",
+ "tinyglobby": "^0.2.15",
+ "tinyrainbow": "^3.1.0",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@opentelemetry/api": "^1.9.0",
+ "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
+ "@vitest/browser-playwright": "4.1.11",
+ "@vitest/browser-preview": "4.1.11",
+ "@vitest/browser-webdriverio": "4.1.11",
+ "@vitest/coverage-istanbul": "4.1.11",
+ "@vitest/coverage-v8": "4.1.11",
+ "@vitest/ui": "4.1.11",
+ "happy-dom": "*",
+ "jsdom": "*",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser-playwright": {
+ "optional": true
+ },
+ "@vitest/browser-preview": {
+ "optional": true
+ },
+ "@vitest/browser-webdriverio": {
+ "optional": true
+ },
+ "@vitest/coverage-istanbul": {
+ "optional": true
+ },
+ "@vitest/coverage-v8": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ },
+ "vite": {
+ "optional": false
+ }
}
},
"node_modules/wasmbuilder": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.16.tgz",
"integrity": "sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==",
- "dev": true
+ "dev": true,
+ "license": "GPL-3.0",
+ "optional": true
},
"node_modules/wasmcurves": {
"version": "0.2.2",
- "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.2.tgz",
- "integrity": "sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==",
+ "resolved": "git+https://github.com/iden3/wasmcurves.git#13d4acc125b794a4e28a5dc1ea99f015d863ec98",
+ "integrity": "sha512-HYvEBTL7NaGyLvhCT3as3/SIFWloyB+4iUy4wt3OSwTgK7jQXNRiXcHXsUwSCtLDPOnU9qX/gI+EKb5/UFyw4g==",
"dev": true,
+ "license": "GPL-3.0",
+ "optional": true,
"dependencies": {
"wasmbuilder": "0.0.16"
}
},
"node_modules/web-worker": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
- "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==",
- "dev": true
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
+ "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/workerpool": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
- "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
- "dev": true
- },
- "node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
- },
- "node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
"engines": {
- "node": ">=10"
+ "node": ">= 8"
}
},
- "node_modules/yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "node_modules/why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
},
"engines": {
- "node": ">=10"
+ "node": ">=8"
}
},
- "node_modules/yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=0.10.0"
}
},
- "node_modules/yargs-unparser": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
- "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "node_modules/ws": {
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"dev": true,
- "dependencies": {
- "camelcase": "^6.0.0",
- "decamelize": "^4.0.0",
- "flat": "^5.0.2",
- "is-plain-obj": "^2.1.0"
- },
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
}
}
},
"dependencies": {
- "@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
+ "@blazediff/core": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz",
+ "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==",
"dev": true
},
+ "@emnapi/core": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
+ "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "@emnapi/wasi-threads": "1.2.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "@emnapi/runtime": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
+ "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "@emnapi/wasi-threads": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "tslib": "^2.4.0"
+ }
+ },
"@eslint-community/eslint-utils": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz",
- "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
"dev": true,
"requires": {
- "eslint-visitor-keys": "^3.3.0"
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true
+ }
}
},
"@eslint-community/regexpp": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz",
- "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==",
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
"dev": true
},
- "@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "@eslint/config-array": {
+ "version": "0.23.5",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz",
+ "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==",
"dev": true,
"requires": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
+ "@eslint/object-schema": "^3.0.5",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.4"
+ }
+ },
+ "@eslint/config-helpers": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz",
+ "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==",
+ "dev": true,
+ "requires": {
+ "@eslint/core": "^1.2.1"
+ }
+ },
+ "@eslint/core": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
+ "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.15"
}
},
"@eslint/js": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
- "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
+ "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
+ "dev": true,
+ "requires": {}
+ },
+ "@eslint/object-schema": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
+ "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==",
"dev": true
},
- "@humanwhocodes/config-array": {
- "version": "0.11.13",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
- "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
+ "@eslint/plugin-kit": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz",
+ "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==",
+ "dev": true,
+ "requires": {
+ "@eslint/core": "^1.2.1",
+ "levn": "^0.4.1"
+ }
+ },
+ "@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
+ "requires": {
+ "@humanfs/types": "^0.15.0"
+ }
+ },
+ "@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
"dev": true,
"requires": {
- "@humanwhocodes/object-schema": "^2.0.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
}
},
+ "@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true
+ },
"@humanwhocodes/module-importer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true
},
- "@humanwhocodes/object-schema": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
- "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
+ "@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true
},
- "@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true
+ },
+ "@napi-rs/wasm-runtime": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
+ "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
"dev": true,
+ "optional": true,
"requires": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
+ "@tybys/wasm-util": "^0.10.3"
}
},
- "@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "@oxc-project/types": {
+ "version": "0.137.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz",
+ "integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==",
+ "dev": true
+ },
+ "@polka/url": {
+ "version": "1.0.0-next.29",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
"dev": true
},
- "@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "@rolldown/binding-android-arm64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz",
+ "integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==",
"dev": true,
- "requires": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- }
+ "optional": true
},
- "@ungap/structured-clone": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
- "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
- "dev": true
+ "@rolldown/binding-darwin-arm64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz",
+ "integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==",
+ "dev": true,
+ "optional": true
},
- "acorn": {
- "version": "8.11.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",
- "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",
+ "@rolldown/binding-darwin-x64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz",
+ "integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==",
"dev": true,
- "peer": true
+ "optional": true
},
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "@rolldown/binding-freebsd-x64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz",
+ "integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==",
"dev": true,
- "requires": {}
+ "optional": true
},
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz",
+ "integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz",
+ "integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-linux-arm64-musl": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz",
+ "integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-linux-ppc64-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz",
+ "integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-linux-s390x-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz",
+ "integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-linux-x64-gnu": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz",
+ "integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-linux-x64-musl": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz",
+ "integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-openharmony-arm64": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz",
+ "integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-wasm32-wasi": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz",
+ "integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==",
"dev": true,
+ "optional": true,
"requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
+ "@emnapi/core": "1.11.1",
+ "@emnapi/runtime": "1.11.1",
+ "@napi-rs/wasm-runtime": "^1.1.6"
}
},
- "ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz",
+ "integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/binding-win32-x64-msvc": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz",
+ "integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==",
+ "dev": true,
+ "optional": true
+ },
+ "@rolldown/pluginutils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
"dev": true
},
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
"dev": true
},
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "@tybys/wasm-util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
+ "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
"dev": true,
+ "optional": true,
"requires": {
- "color-convert": "^2.0.1"
+ "tslib": "^2.4.0"
}
},
- "anymatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
- "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "@types/chai": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+ "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
"dev": true,
"requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
+ "@types/deep-eql": "*",
+ "assertion-error": "^2.0.1"
}
},
- "assertion-error": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
- "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+ "@types/deep-eql": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
"dev": true
},
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "@types/esrecurse": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+ "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
"dev": true
},
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
"dev": true
},
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true
+ },
+ "@vitest/browser": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.11.tgz",
+ "integrity": "sha512-bwMovvAeuTFOK5kIFevw4VEf+1gVEICv4SYK4k3knJOxl6b1zEWud8mYKD73e1B0odAn174h1MofURy2TPWf3w==",
"dev": true,
"requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "@blazediff/core": "1.9.1",
+ "@vitest/mocker": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "magic-string": "^0.30.21",
+ "pngjs": "^7.0.0",
+ "sirv": "^3.0.2",
+ "tinyrainbow": "^3.1.0",
+ "ws": "^8.19.0"
}
},
- "braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "@vitest/browser-playwright": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.11.tgz",
+ "integrity": "sha512-riLBxPqwnJ0lWs2DN2WeUfYeKLoAjbP2Xx8cLQdSddzMi20sksIa6K2mPz79DyMZKKVKH2ksOC2yJvtNcZg8cg==",
"dev": true,
"requires": {
- "fill-range": "^7.1.1"
+ "@vitest/browser": "4.1.11",
+ "@vitest/mocker": "4.1.11",
+ "tinyrainbow": "^3.1.0"
}
},
- "browser-stdout": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
- "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
- "dev": true
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true
- },
- "camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true
+ "@vitest/expect": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
+ "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
+ "dev": true,
+ "requires": {
+ "@standard-schema/spec": "^1.1.0",
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "chai": "^6.2.2",
+ "tinyrainbow": "^3.1.0"
+ }
},
- "chai": {
- "version": "4.3.10",
- "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
- "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
+ "@vitest/mocker": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
+ "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
"dev": true,
- "peer": true,
"requires": {
- "assertion-error": "^1.1.0",
- "check-error": "^1.0.3",
- "deep-eql": "^4.1.3",
- "get-func-name": "^2.0.2",
- "loupe": "^2.3.6",
- "pathval": "^1.1.1",
- "type-detect": "^4.0.8"
+ "@vitest/spy": "4.1.11",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
}
},
- "chai-as-promised": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz",
- "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==",
+ "@vitest/pretty-format": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
+ "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
"dev": true,
"requires": {
- "check-error": "^1.0.2"
+ "tinyrainbow": "^3.1.0"
}
},
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "@vitest/runner": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
+ "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
"dev": true,
"requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
+ "@vitest/utils": "4.1.11",
+ "pathe": "^2.0.3"
}
},
- "check-error": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
- "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==",
+ "@vitest/snapshot": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
+ "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
"dev": true,
"requires": {
- "get-func-name": "^2.0.2"
+ "@vitest/pretty-format": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "magic-string": "^0.30.21",
+ "pathe": "^2.0.3"
}
},
- "chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "@vitest/spy": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
+ "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
+ "dev": true
+ },
+ "@vitest/utils": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
+ "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
"dev": true,
"requires": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "fsevents": "~2.3.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
+ "@vitest/pretty-format": "4.1.11",
+ "convert-source-map": "^2.0.0",
+ "tinyrainbow": "^3.1.0"
}
},
- "cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "acorn": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
+ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"dev": true,
"requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
}
},
- "color-convert": {
+ "assertion-error": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"dev": true,
"requires": {
- "color-name": "~1.1.4"
+ "balanced-match": "^4.0.2"
}
},
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "chai": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+ "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
"dev": true
},
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
"cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
@@ -2124,27 +2907,12 @@
}
},
"debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "decamelize": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
- "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
- "dev": true
- },
- "deep-eql": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
- "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"requires": {
- "type-detect": "^4.0.0"
+ "ms": "^2.1.3"
}
},
"deep-is": {
@@ -2153,31 +2921,16 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
- "diff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
- "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
- "dev": true
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"dev": true
},
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "es-module-lexer": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz",
+ "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==",
"dev": true
},
"escape-string-regexp": {
@@ -2187,50 +2940,41 @@
"dev": true
},
"eslint": {
- "version": "8.56.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
- "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
- "dev": true,
- "peer": true,
- "requires": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.56.0",
- "@humanwhocodes/config-array": "^0.11.13",
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.6.0.tgz",
+ "integrity": "sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==",
+ "dev": true,
+ "requires": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@eslint/config-array": "^0.23.5",
+ "@eslint/config-helpers": "^0.6.0",
+ "@eslint/core": "^1.2.1",
+ "@eslint/plugin-kit": "^0.7.2",
+ "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "cross-spawn": "^7.0.6",
"debug": "^4.3.2",
- "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
+ "eslint-scope": "^9.1.2",
+ "eslint-visitor-keys": "^5.0.1",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
+ "file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
+ "minimatch": "^3.1.4",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
+ "optionator": "^0.9.3"
},
"dependencies": {
"glob-parent": {
@@ -2245,36 +2989,38 @@
}
},
"eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+ "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
"dev": true,
"requires": {
+ "@types/esrecurse": "^4.3.1",
+ "@types/estree": "^1.0.8",
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
}
},
"eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true
},
"espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
"requires": {
- "acorn": "^8.9.0",
+ "acorn": "^8.16.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "eslint-visitor-keys": "^5.0.1"
}
},
"esquery": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz",
- "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==",
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
@@ -2295,12 +3041,27 @@
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true
},
+ "estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "requires": {
+ "@types/estree": "^1.0.0"
+ }
+ },
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "expect-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
+ "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==",
+ "dev": true
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2319,210 +3080,83 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
- "fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
- "requires": {
- "reusify": "^1.0.4"
- }
- },
"ffjavascript": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.3.0.tgz",
- "integrity": "sha512-l7sR5kmU3gRwDy8g0Z2tYBXy5ttmafRPFOqY7S6af5cq51JqJWt5eQ/lSR/rs2wQNbDYaYlQr5O+OSUf/oMLoQ==",
+ "version": "git+https://github.com/iden3/ffjavascript.git#cc88563e1686646616ad0fcfafa6cb09c879dd25",
+ "integrity": "sha512-CLLd+R83k5OOIj14sPLlxlLX8YwuOFUn51Rt3XwQIegHbQyga5fMZ8DO/uCx/jVZzm1NEqSaevmQO7VNW8KVtA==",
"dev": true,
+ "from": "ffjavascript@git+https://github.com/iden3/ffjavascript.git#cc88563e1686646616ad0fcfafa6cb09c879dd25",
"requires": {
"wasmbuilder": "0.0.16",
- "wasmcurves": "0.2.2",
- "web-worker": "1.2.0"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
+ "wasmcurves": "git+https://github.com/iden3/wasmcurves.git#13d4acc125b794a4e28a5dc1ea99f015d863ec98",
+ "web-worker": "1.5.0"
}
},
- "flat": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
- "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
- "dev": true
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz",
- "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==",
- "dev": true
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
- "dev": true
- },
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
- "get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true
- },
- "get-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
- "dev": true
- },
- "glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
"requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "flat-cache": "^4.0.0"
}
},
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"requires": {
- "is-glob": "^4.0.1"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
}
},
- "globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
"requires": {
- "type-fest": "^0.20.2"
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
}
},
- "graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "flatted": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true
},
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
},
- "he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "globals": {
+ "version": "17.7.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz",
+ "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==",
"dev": true
},
"ignore": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
- "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true
},
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true,
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true
},
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
},
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -2532,52 +3166,17 @@
"is-extglob": "^2.1.1"
}
},
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
- },
- "is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true
- },
- "is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
- "dev": true
- },
- "is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
- "dev": true
- },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
- "js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "requires": {
- "argparse": "^2.0.1"
- },
- "dependencies": {
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- }
- }
+ "json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -2588,9 +3187,18 @@
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
+ "keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "requires": {
+ "json-buffer": "3.0.1"
+ }
+ },
"levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -2601,158 +3209,172 @@
"type-check": "~0.4.0"
}
},
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
"dev": true,
"requires": {
- "p-locate": "^5.0.0"
+ "detect-libc": "^2.0.3",
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
}
},
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
+ "lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "dev": true,
+ "optional": true
},
- "log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
"dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- }
+ "optional": true
+ },
+ "lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "dev": true,
+ "optional": true
},
- "loupe": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
- "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+ "lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "dev": true,
+ "optional": true
+ },
+ "lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "dev": true,
+ "optional": true
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
"requires": {
- "get-func-name": "^2.0.0"
+ "p-locate": "^5.0.0"
}
},
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"requires": {
- "brace-expansion": "^1.1.7"
+ "@jridgewell/sourcemap-codec": "^1.5.5"
}
},
- "mocha": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
- "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==",
+ "minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"dev": true,
"requires": {
- "ansi-colors": "4.1.1",
- "browser-stdout": "1.3.1",
- "chokidar": "3.5.3",
- "debug": "4.3.4",
- "diff": "5.0.0",
- "escape-string-regexp": "4.0.0",
- "find-up": "5.0.0",
- "glob": "7.2.0",
- "he": "1.2.0",
- "js-yaml": "4.1.0",
- "log-symbols": "4.1.0",
- "minimatch": "5.0.1",
- "ms": "2.1.3",
- "nanoid": "3.3.3",
- "serialize-javascript": "6.0.0",
- "strip-json-comments": "3.1.1",
- "supports-color": "8.1.1",
- "workerpool": "6.2.1",
- "yargs": "16.2.0",
- "yargs-parser": "20.2.4",
- "yargs-unparser": "2.0.0"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
- "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
- "dev": true,
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- },
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
+ "brace-expansion": "^5.0.9"
}
},
+ "mrmime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+ "dev": true
+ },
"ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
},
"nanoid": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
- "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
"dev": true
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "obug": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz",
+ "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==",
"dev": true
},
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
- "requires": {
- "wrappy": "1"
- }
- },
"optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
"requires": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
}
},
"p-limit": {
@@ -2779,139 +3401,104 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "requires": {
- "callsites": "^3.0.0"
- }
- },
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
- "dev": true
- },
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
- "pathval": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
- "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
- "dev": true
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true
},
- "punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true
},
- "queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
"dev": true
},
- "randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "dev": true,
- "requires": {
- "safe-buffer": "^5.1.0"
- }
- },
- "readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "playwright": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz",
+ "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==",
"dev": true,
"requires": {
- "picomatch": "^2.2.1"
+ "fsevents": "2.3.2",
+ "playwright-core": "1.61.1"
}
},
- "require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
- "dev": true
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "playwright-core": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz",
+ "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==",
"dev": true
},
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "pngjs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
+ "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
"dev": true
},
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "postcss": {
+ "version": "8.5.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
+ "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
"dev": true,
"requires": {
- "fsevents": "~2.3.2"
+ "nanoid": "^3.3.17",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
}
},
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "requires": {
- "queue-microtask": "^1.2.2"
- }
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true
},
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true
},
- "serialize-javascript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
- "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
+ "rolldown": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz",
+ "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==",
"dev": true,
"requires": {
- "randombytes": "^2.1.0"
+ "@oxc-project/types": "=0.137.0",
+ "@rolldown/binding-android-arm64": "1.1.3",
+ "@rolldown/binding-darwin-arm64": "1.1.3",
+ "@rolldown/binding-darwin-x64": "1.1.3",
+ "@rolldown/binding-freebsd-x64": "1.1.3",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.1.3",
+ "@rolldown/binding-linux-arm64-gnu": "1.1.3",
+ "@rolldown/binding-linux-arm64-musl": "1.1.3",
+ "@rolldown/binding-linux-ppc64-gnu": "1.1.3",
+ "@rolldown/binding-linux-s390x-gnu": "1.1.3",
+ "@rolldown/binding-linux-x64-gnu": "1.1.3",
+ "@rolldown/binding-linux-x64-musl": "1.1.3",
+ "@rolldown/binding-openharmony-arm64": "1.1.3",
+ "@rolldown/binding-wasm32-wasi": "1.1.3",
+ "@rolldown/binding-win32-arm64-msvc": "1.1.3",
+ "@rolldown/binding-win32-x64-msvc": "1.1.3",
+ "@rolldown/pluginutils": "^1.0.0"
}
},
"shebang-command": {
@@ -2929,55 +3516,90 @@
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
+ "siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true
},
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "sirv": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+ "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
"dev": true,
"requires": {
- "ansi-regex": "^5.0.1"
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
}
},
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true
+ },
+ "stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true
+ },
+ "std-env": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz",
+ "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==",
+ "dev": true
+ },
+ "tinybench": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"dev": true
},
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "tinyexec": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz",
+ "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==",
+ "dev": true
+ },
+ "tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
"dev": true,
"requires": {
- "has-flag": "^4.0.0"
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "dependencies": {
+ "fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "requires": {}
+ }
}
},
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "tinyrainbow": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz",
+ "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==",
"dev": true
},
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "dev": true
+ },
+ "tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
- "requires": {
- "is-number": "^7.0.0"
- }
+ "optional": true
},
"type-check": {
"version": "0.4.0",
@@ -2988,18 +3610,6 @@
"prelude-ls": "^1.2.1"
}
},
- "type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
- "dev": true
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true
- },
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -3009,25 +3619,78 @@
"punycode": "^2.1.0"
}
},
+ "vite": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.0.tgz",
+ "integrity": "sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==",
+ "dev": true,
+ "requires": {
+ "fsevents": "~2.3.3",
+ "lightningcss": "^1.32.0",
+ "picomatch": "^4.0.4",
+ "postcss": "^8.5.26",
+ "rolldown": "~1.1.2",
+ "tinyglobby": "^0.2.17"
+ },
+ "dependencies": {
+ "fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "vitest": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
+ "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
+ "dev": true,
+ "requires": {
+ "@vitest/expect": "4.1.11",
+ "@vitest/mocker": "4.1.11",
+ "@vitest/pretty-format": "4.1.11",
+ "@vitest/runner": "4.1.11",
+ "@vitest/snapshot": "4.1.11",
+ "@vitest/spy": "4.1.11",
+ "@vitest/utils": "4.1.11",
+ "es-module-lexer": "^2.0.0",
+ "expect-type": "^1.3.0",
+ "magic-string": "^0.30.21",
+ "obug": "^2.1.1",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3",
+ "std-env": "^4.0.0-rc.1",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^1.0.2",
+ "tinyglobby": "^0.2.15",
+ "tinyrainbow": "^3.1.0",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "why-is-node-running": "^2.3.0"
+ }
+ },
"wasmbuilder": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.16.tgz",
"integrity": "sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"wasmcurves": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.2.tgz",
- "integrity": "sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==",
+ "version": "git+https://github.com/iden3/wasmcurves.git#13d4acc125b794a4e28a5dc1ea99f015d863ec98",
+ "integrity": "sha512-HYvEBTL7NaGyLvhCT3as3/SIFWloyB+4iUy4wt3OSwTgK7jQXNRiXcHXsUwSCtLDPOnU9qX/gI+EKb5/UFyw4g==",
"dev": true,
+ "from": "wasmcurves@git+https://github.com/iden3/wasmcurves.git#13d4acc125b794a4e28a5dc1ea99f015d863ec98",
+ "optional": true,
"requires": {
"wasmbuilder": "0.0.16"
}
},
"web-worker": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz",
- "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
+ "integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
"dev": true
},
"which": {
@@ -3039,67 +3702,28 @@
"isexe": "^2.0.0"
}
},
- "workerpool": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
- "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
- "dev": true
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
- },
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true
- },
- "yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
"requires": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
}
},
- "yargs-parser": {
- "version": "20.2.4",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
- "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+ "word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true
},
- "yargs-unparser": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
- "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
+ "ws": {
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"dev": true,
- "requires": {
- "camelcase": "^6.0.0",
- "decamelize": "^4.0.0",
- "flat": "^5.0.2",
- "is-plain-obj": "^2.1.0"
- }
+ "requires": {}
}
}
}
diff --git a/package.json b/package.json
index b8c0049..6e8a046 100644
--- a/package.json
+++ b/package.json
@@ -3,16 +3,32 @@
"type": "module",
"version": "0.0.20",
"description": "fast cached read write of big binary files",
- "main": "./build/main.cjs",
+ "main": "./build/node/main.cjs",
"module": "./src/fastfile.js",
"exports": {
- "import": "./src/fastfile.js",
- "require": "./build/main.cjs"
+ ".": {
+ "node": {
+ "import": "./src/fastfile.js",
+ "require": "./build/node/main.cjs"
+ },
+ "browser": {
+ "import": "./build/browser/browser.esm.js",
+ "default": "./build/browser/browser.iife.js"
+ },
+ "default": "./src/fastfile.js"
+ }
},
"scripts": {
- "pretest": "eslint .",
- "test": "mocha",
- "build": "rollup -c rollup.cjs.config.js"
+ "lint": "eslint .",
+ "pretest": "npm run build && npm run lint",
+ "test": "vitest run",
+ "test:node": "vitest run --project node-esm --project node-cjs",
+ "test:browser": "vitest run --project browser-esm",
+ "test:watch": "vitest",
+ "test:integration": "vitest run test/test.js --testTimeout=1000000000",
+ "build:node": "vite build --mode node",
+ "build:browser": "vite build --mode browser",
+ "build": "npm run build:node && npm run build:browser"
},
"keywords": [
"file",
@@ -24,17 +40,26 @@
],
"author": "0kims",
"license": "GPL-3.0",
- "dependencies": {},
"repository": {
"type": "git",
"url": "https://github.com/iden3/fastfile.git"
},
"devDependencies": {
- "eslint": "^8.17.0",
- "ffjavascript": "^0.3.0",
- "mocha": "^10.0.0",
- "chai": "^4.3.6",
- "chai-as-promised": "^7.1.1",
- "rollup": "^2.20.0"
+ "@eslint/js": "^10.0.1",
+ "@vitest/browser": "^4.1.11",
+ "@vitest/browser-playwright": "^4.1.11",
+ "eslint": "^10.1.0",
+ "ffjavascript": "git+https://github.com/iden3/ffjavascript.git#cc88563e1686646616ad0fcfafa6cb09c879dd25",
+ "globals": "^17.4.0",
+ "playwright": "^1.59.0",
+ "vite": "^8.0.3",
+ "vitest": "^4.1.11"
+ },
+ "overrides": {
+ "serialize-javascript": "^7.0.5",
+ "diff": "^8.0.3",
+ "minimatch": "^3.1.4",
+ "postcss": "^8.5.26",
+ "brace-expansion": "^5.0.9"
}
}
diff --git a/rollup.cjs.config.js b/rollup.cjs.config.js
deleted file mode 100644
index e3f40b6..0000000
--- a/rollup.cjs.config.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import fs from "fs";
-import { builtinModules as builtin } from "module";
-
-const pkg = JSON.parse(fs.readFileSync("./package.json"));
-
-export default {
- input: "./src/fastfile.js",
- output: {
- file: "build/main.cjs",
- format: "cjs",
- },
- external: [
- ...Object.keys(pkg.dependencies),
- ...builtin,
- ]
-};
diff --git a/src/bigmemfile.js b/src/bigmemfile.js
index 8513db0..d483c52 100644
--- a/src/bigmemfile.js
+++ b/src/bigmemfile.js
@@ -208,6 +208,13 @@ class BigMemFile {
}
let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage);
+ if (readLength <= 0) {
+ // EOF without a terminator: the string ends at the end of the
+ // data (matches the rangefile backend). This used to spin
+ // forever re-reading an empty window.
+ self.pos = currentPosition;
+ return str;
+ }
const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength);
let indexEndOfString = dataArray.findIndex(element => element === 0);
diff --git a/src/blobfile.js b/src/blobfile.js
new file mode 100644
index 0000000..0fd13eb
--- /dev/null
+++ b/src/blobfile.js
@@ -0,0 +1,25 @@
+// Read-only file over a Blob/File (e.g. a browser
+// selection). blob.slice() is a zero-copy view; bytes only reach memory when
+// a sub-range is read, so large zkeys stream from disk chunk-by-chunk with
+// the same bounded footprint as the Node file backend.
+
+import { RangeFile } from "./rangefile.js";
+
+// Same rationale as httpfile's cap, relaxed for a local source: callers pass
+// disk-tuned page sizes (MiBs) that would make every small header read
+// materialize a huge slice; 1 MiB keeps that bounded while costing at most a
+// handful of slice reads per file open.
+const MAX_BLOB_PAGE_SIZE = 1 << 20;
+
+export function readExisting(o) {
+ const blob = o.blob;
+ const readRangeInto = async function (dst, dstOffset, pos, len) {
+ const ab = await blob.slice(pos, pos + len).arrayBuffer();
+ if (ab.byteLength !== len) {
+ throw new Error("short blob read (" + ab.byteLength + "/" + len + " bytes at " + pos + ")");
+ }
+ dst.set(new Uint8Array(ab), dstOffset);
+ };
+ const pageSize = Math.min(o.pageSize || MAX_BLOB_PAGE_SIZE, MAX_BLOB_PAGE_SIZE);
+ return new RangeFile(readRangeInto, blob.size, o.cacheSize, pageSize);
+}
diff --git a/src/fastfile.browser.js b/src/fastfile.browser.js
new file mode 100644
index 0000000..b7dba5c
--- /dev/null
+++ b/src/fastfile.browser.js
@@ -0,0 +1,55 @@
+import * as memFile from "./memfile.js";
+import * as bigMemFile from "./bigmemfile.js";
+import * as httpFile from "./httpfile.js";
+import * as blobFile from "./blobfile.js";
+
+function noFileSupport() {
+ throw new Error("File I/O is not supported in the browser");
+}
+
+function normalizeOpts(o) {
+ if (o instanceof Uint8Array) return { type: "mem", data: o };
+ // A string means a file path/name in the Node API. There are no files in
+ // the browser, so reject it instead of silently creating an anonymous mem
+ // file (which would mask code copied from the Node README).
+ if (typeof o === "string") noFileSupport();
+ return o;
+}
+
+function dispatchMem(o, memFn, bigMemFn) {
+ if (o.type === "file") noFileSupport();
+ if (o.type === "mem") return memFn(o);
+ if (o.type === "bigMem") return bigMemFn(o);
+ throw new Error("Invalid FastFile type: " + o.type);
+}
+
+export function createOverride(o) {
+ return dispatchMem(normalizeOpts(o), memFile.createNew, bigMemFile.createNew);
+}
+
+export const createNoOverride = createOverride;
+
+export async function readExisting(o, b, c) {
+ if (o instanceof Uint8Array) {
+ o = { type: "mem", data: o };
+ }
+ if (typeof Blob !== "undefined" && o instanceof Blob) {
+ o = { type: "blob", blob: o, cacheSize: b, pageSize: c };
+ }
+ if (typeof o === "string") {
+ // URLs (historically fetched whole) go through the http backend: it
+ // streams via Range requests when the server supports them and falls
+ // back to buffering the full body when it does not.
+ o = { type: "http", url: o, cacheSize: b, pageSize: c };
+ }
+ if (o.type === "http") return await httpFile.readExisting(o);
+ if (o.type === "blob") return blobFile.readExisting(o);
+ return dispatchMem(o, memFile.readExisting, bigMemFile.readExisting);
+}
+
+export function readWriteExisting(o) {
+ if (typeof o === "string") noFileSupport();
+ return dispatchMem(o, memFile.readWriteExisting, bigMemFile.readWriteExisting);
+}
+
+export const readWriteExistingOrCreate = readWriteExisting;
diff --git a/src/fastfile.js b/src/fastfile.js
index d065634..afb639a 100644
--- a/src/fastfile.js
+++ b/src/fastfile.js
@@ -1,12 +1,40 @@
import { open } from "./osfile.js";
import * as memFile from "./memfile.js";
import * as bigMemFile from "./bigmemfile.js";
+import * as httpFile from "./httpfile.js";
+import * as blobFile from "./blobfile.js";
import { O_TRUNC, O_CREAT, O_RDWR, O_EXCL, O_RDONLY } from "constants";
const DEFAULT_CACHE_SIZE = (1 << 16);
const DEFAULT_PAGE_SIZE = (1 << 13);
+// Robust Node detection that never throws (unlike `process.browser`, which is a
+// webpack-ism and is undefined under Vite/esbuild/SES).
+const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
+
+// The b/c arguments are the caller's cacheSize/pageSize hints. Historically
+// they were only applied while coercing string (and Blob) sources into
+// descriptor objects, so a caller passing {type: "file"|"http"} without
+// explicit sizes silently fell back to the small built-in defaults even when
+// it supplied tuned hints for the string case. Fill exactly the fields the
+// descriptor leaves undefined; never mutate the caller's object.
+function withSizeFallbacks(o, b, c) {
+ if (typeof o !== "object" || o === null) return o;
+ // Only the page-cache backends consume these sizes. mem/bigMem
+ // descriptors must pass through UNTOUCHED and by identity: the mem
+ // backend stores the written data on the caller's object (o.data), so
+ // handing a copy to createNew would leave the caller's descriptor empty.
+ if (o.type !== "file" && o.type !== "http" && o.type !== "blob") return o;
+ const needCache = o.cacheSize === undefined && b !== undefined;
+ const needPage = o.pageSize === undefined && c !== undefined;
+ if (!needCache && !needPage) return o;
+ const res = Object.assign({}, o);
+ if (needCache) res.cacheSize = b;
+ if (needPage) res.pageSize = c;
+ return res;
+}
+
export async function createOverride(o, b, c) {
if (typeof o === "string") {
@@ -17,6 +45,7 @@ export async function createOverride(o, b, c) {
pageSize: c || DEFAULT_PAGE_SIZE
};
}
+ o = withSizeFallbacks(o, b, c);
if (o.type == "file") {
return await open(o.fileName, O_TRUNC | O_CREAT | O_RDWR, o.cacheSize, o.pageSize);
} else if (o.type == "mem") {
@@ -24,7 +53,7 @@ export async function createOverride(o, b, c) {
} else if (o.type == "bigMem") {
return bigMemFile.createNew(o);
} else {
- throw new Error("Invalid FastFile type: " + o.type);
+ throw new Error("Invalid FastFile type: "+o.type);
}
}
@@ -37,6 +66,7 @@ export function createNoOverride(o, b, c) {
pageSize: c || DEFAULT_PAGE_SIZE
};
}
+ o = withSizeFallbacks(o, b, c);
if (o.type == "file") {
return open(o.fileName, O_TRUNC | O_CREAT | O_RDWR | O_EXCL, o.cacheSize, o.pageSize);
} else if (o.type == "mem") {
@@ -44,7 +74,7 @@ export function createNoOverride(o, b, c) {
} else if (o.type == "bigMem") {
return bigMemFile.createNew(o);
} else {
- throw new Error("Invalid FastFile type: " + o.type);
+ throw new Error("Invalid FastFile type: "+o.type);
}
}
@@ -55,20 +85,27 @@ export async function readExisting(o, b, c) {
data: o
};
}
- if (process.browser) {
- if (typeof o === "string") {
- const buff = await fetch(o).then(function (res) {
- return res.arrayBuffer();
- }).then(function (ab) {
- return new Uint8Array(ab);
- });
+ if (typeof Blob !== "undefined" && o instanceof Blob) {
+ o = {
+ type: "blob",
+ blob: o,
+ cacheSize: b,
+ pageSize: c
+ };
+ }
+ if (typeof o === "string") {
+ // URLs (and, in the browser, any string -- historically fetched
+ // whole) go through the http backend: it streams via Range requests
+ // when the server supports them and falls back to buffering the
+ // full body (the previous behavior) when it does not.
+ if (!isNode || /^https?:\/\//i.test(o)) {
o = {
- type: "mem",
- data: buff
+ type: "http",
+ url: o,
+ cacheSize: b,
+ pageSize: c
};
- }
- } else {
- if (typeof o === "string") {
+ } else {
o = {
type: "file",
fileName: o,
@@ -77,14 +114,19 @@ export async function readExisting(o, b, c) {
};
}
}
+ o = withSizeFallbacks(o, b, c);
if (o.type == "file") {
return await open(o.fileName, O_RDONLY, o.cacheSize, o.pageSize);
} else if (o.type == "mem") {
return await memFile.readExisting(o);
} else if (o.type == "bigMem") {
return await bigMemFile.readExisting(o);
+ } else if (o.type == "http") {
+ return await httpFile.readExisting(o);
+ } else if (o.type == "blob") {
+ return blobFile.readExisting(o);
} else {
- throw new Error("Invalid FastFile type: " + o.type);
+ throw new Error("Invalid FastFile type: "+o.type);
}
}
@@ -97,6 +139,7 @@ export function readWriteExisting(o, b, c) {
pageSize: c || DEFAULT_PAGE_SIZE
};
}
+ o = withSizeFallbacks(o, b, c);
if (o.type == "file") {
return open(o.fileName, O_CREAT | O_RDWR, o.cacheSize, o.pageSize);
} else if (o.type == "mem") {
@@ -104,7 +147,7 @@ export function readWriteExisting(o, b, c) {
} else if (o.type == "bigMem") {
return bigMemFile.readWriteExisting(o);
} else {
- throw new Error("Invalid FastFile type: " + o.type);
+ throw new Error("Invalid FastFile type: "+o.type);
}
}
@@ -117,6 +160,7 @@ export function readWriteExistingOrCreate(o, b, c) {
pageSize: c || DEFAULT_PAGE_SIZE
};
}
+ o = withSizeFallbacks(o, b, c);
if (o.type == "file") {
return open(o.fileName, O_CREAT | O_RDWR | O_EXCL, o.cacheSize);
} else if (o.type == "mem") {
@@ -124,6 +168,6 @@ export function readWriteExistingOrCreate(o, b, c) {
} else if (o.type == "bigMem") {
return bigMemFile.readWriteExisting(o);
} else {
- throw new Error("Invalid FastFile type: " + o.type);
+ throw new Error("Invalid FastFile type: "+o.type);
}
}
diff --git a/src/httpfile.js b/src/httpfile.js
new file mode 100644
index 0000000..1d003ce
--- /dev/null
+++ b/src/httpfile.js
@@ -0,0 +1,336 @@
+// Read-only file over HTTP(S) using Range requests.
+//
+// Open probes the server with `Range: bytes=0-0`:
+// - 206 + parseable Content-Range total -> a RangeFile whose reads become
+// range requests; large reads (zkey/ptau sections, MSM chunks) stream
+// the response body straight into the caller's buffer, so the full file
+// is never resident;
+// - anything else (200, no range support, unknown total) -> fall back to
+// buffering the body in memory, i.e. the historical browser behavior.
+//
+// Consistency: the validator captured at open (strong ETag, else
+// Last-Modified) is sent as If-Range on every range request. If the remote
+// file changes mid-read the server answers 200 instead of 206 and the read
+// throws, rather than silently mixing chunks of two file versions.
+//
+// Server requirements (CORS deployments): allow the `Range`, `If-Range`,
+// `If-None-Match` and `If-Modified-Since` request headers and expose
+// `Content-Range` + `ETag`; serve zkeys without Content-Encoding (ranges
+// address encoded bytes). A missing allow-list entry for the conditional
+// headers only costs the 304 warm-start (the probe retries unconditionally).
+
+import { RangeFile } from "./rangefile.js";
+import * as memFile from "./memfile.js";
+import { wrapWithPersistentCache, peekPersistentMeta, persistFullBody } from "./idbcache.js";
+
+// Callers tune cacheSize/pageSize for the disk backend (snarkjs passes 8 MiB
+// pages); over HTTP a page that large turns a 4-byte header read into a
+// megabytes-range request -- for files below the page size, the whole file in
+// one response, defeating streaming. Cap pages at 64 KiB: big enough to
+// coalesce a binfile section-table scan, small enough to stay incidental.
+// Reads >= the page size bypass the cache entirely (RangeFile direct path),
+// so large section/chunk reads are unaffected by the cap.
+const MAX_HTTP_PAGE_SIZE = 1 << 16;
+
+export async function readExisting(o) {
+ const url = o.url;
+ // With the persistent cache on, probe conditionally: if we hold cached
+ // blocks for this URL, an unchanged file answers 304 with no body --
+ // which is what makes warm starts work even against servers that ignore
+ // Range and would otherwise ship the entire file in the probe response.
+ const cacheMeta = o.cache
+ ? await peekPersistentMeta({ fileKey: url, options: o.cache })
+ : null;
+ const probeHeaders = { "Range": "bytes=0-0" };
+ if (cacheMeta && cacheMeta.validator) {
+ if (cacheMeta.validator[0] === "\"" || cacheMeta.validator.indexOf("W/") === 0) {
+ probeHeaders["If-None-Match"] = cacheMeta.validator;
+ } else {
+ probeHeaders["If-Modified-Since"] = cacheMeta.validator;
+ }
+ }
+ let probe;
+ try {
+ probe = await fetch(url, { headers: probeHeaders });
+ } catch (err) {
+ // Conditional headers are not CORS-safelisted; a cross-origin server
+ // whose preflight does not allow If-None-Match/If-Modified-Since
+ // fails the fetch outright. Never let the cache break an open that
+ // would work without it: retry unconditionally.
+ if (!("If-None-Match" in probeHeaders) && !("If-Modified-Since" in probeHeaders)) throw err;
+ probe = await fetch(url, { headers: { "Range": "bytes=0-0" } });
+ }
+
+ if (probe.status === 304) {
+ // Unchanged since it was cached. Serve through the cache; missing
+ // blocks go over range requests, or through the degrade-to-full path
+ // when the origin turns out to ignore Range.
+ await abandonBody(probe);
+ return await buildStreamingFile(url, cacheMeta.validator, cacheMeta.totalSize, o);
+ }
+
+ if (probe.status === 206) {
+ const contentRange = probe.headers.get("content-range");
+ const m = contentRange ? /\/(\d+)\s*$/.exec(contentRange) : null;
+ if (m) {
+ const totalSize = parseInt(m[1]);
+ // Drain the 1-byte probe body so the connection can be reused.
+ await probe.arrayBuffer();
+ const validator = strongValidator(probe);
+ return await buildStreamingFile(url, validator, totalSize, o);
+ }
+ // 206 but total size unknown (Content-Range: bytes 0-0/*): we cannot
+ // do bounded positioned reads; refetch whole and buffer.
+ await probe.arrayBuffer();
+ return await readFullyToMem(url);
+ }
+
+ if (!probe.ok && probe.status !== 416) {
+ throw new Error("HTTP " + probe.status + " fetching " + url);
+ }
+
+ if (probe.status === 416) {
+ // Range not satisfiable -- only legitimate for an empty file.
+ const contentRange = probe.headers.get("content-range");
+ if (contentRange && /\/0\s*$/.test(contentRange)) {
+ return memFile.readExisting({ type: "mem", data: new Uint8Array(0) });
+ }
+ return await readFullyToMem(url);
+ }
+
+ // 200: the server ignored Range and sent the whole file; reuse this body.
+ const data = new Uint8Array(await probe.arrayBuffer());
+ if (o.cache) {
+ // Persist the body so the next session's conditional probe gets a
+ // bodyless 304 and reads locally. Best-effort, validator-keyed.
+ const validator = strongValidator(probe);
+ if (validator) {
+ await persistFullBody({
+ fileKey: url,
+ validator: validator,
+ totalSize: data.length,
+ options: o.cache,
+ data: data,
+ });
+ }
+ }
+ return memFile.readExisting({ type: "mem", data: data });
+}
+
+// Positioned reader over range requests with the degrade-to-buffering escape
+// hatch, optionally wrapped with the persistent block cache, presented as a
+// RangeFile. Shared by the fresh (206 probe) and warm (304 probe) paths.
+async function buildStreamingFile(url, validator, totalSize, o) {
+ // Degrade-to-buffering escape hatch: a 206 probe answer can come from an
+ // intermediary (browsers satisfy ranges out of their own HTTP cache of a
+ // full 200), while the origin itself ignores Range. When a later range
+ // request gets a 200 whose strong validator still matches, the file is
+ // unchanged -- buffer that full body once and serve every subsequent
+ // read from it.
+ let fullBody = null;
+ let readRangeInto = async function (dst, dstOffset, pos, len) {
+ if (!fullBody) {
+ try {
+ return await httpReadRangeInto(url, validator, dst, dstOffset, pos, len);
+ } catch (err) {
+ if (!err || !err.degradeToFull) throw err;
+ fullBody = err.fullBodyPromise;
+ }
+ }
+ const data = await fullBody;
+ if (pos + len > data.byteLength) {
+ throw new Error(url + ": read past the end of the buffered body");
+ }
+ dst.set(data.subarray(pos, pos + len), dstOffset);
+ };
+ const pageSize = Math.min(o.pageSize || MAX_HTTP_PAGE_SIZE, MAX_HTTP_PAGE_SIZE);
+ if (o.cache) {
+ // Opt-in warm start: persist fetched blocks in IndexedDB so a later
+ // session against the same URL reads locally. Keyed on the strong
+ // validator -- without one the wrapper declines and this stays a
+ // plain streaming reader.
+ readRangeInto = await wrapWithPersistentCache(readRangeInto, {
+ fileKey: url,
+ validator: validator,
+ totalSize: totalSize,
+ options: o.cache,
+ });
+ }
+ return new RangeFile(readRangeInto, totalSize, o.cacheSize, pageSize);
+}
+
+async function readFullyToMem(url) {
+ const res = await fetch(url);
+ if (!res.ok) throw new Error("HTTP " + res.status + " fetching " + url);
+ const data = new Uint8Array(await res.arrayBuffer());
+ return memFile.readExisting({ type: "mem", data: data });
+}
+
+// Only a strong validator is usable with If-Range (RFC 9110 §13.1.5): a weak
+// ETag would make conditional range requests always fail on some servers.
+function strongValidator(res) {
+ const etag = res.headers.get("etag");
+ if (etag && etag.indexOf("W/") !== 0) return etag;
+ const lastModified = res.headers.get("last-modified");
+ if (lastModified) return lastModified;
+ return null;
+}
+
+// Browsers cap HTTP/1.1 connections per host (Chrome: 6). A prover's
+// read-ahead can put more range requests in flight than that; on a
+// bandwidth-limited link the extra requests then queue behind stalled
+// not-yet-consumed responses and the connection pool deadlocks -- observed
+// as a browser proof of a 1 GiB zkey freezing with exactly six open
+// responses. Cap concurrent range fetches below the browser's limit, and
+// hold each slot until the response body is fully consumed (that is when
+// the connection actually frees).
+const MAX_CONCURRENT_RANGE_FETCHES = 4;
+let activeRangeFetches = 0;
+const rangeFetchQueue = [];
+async function withRangeFetchSlot(fn) {
+ while (activeRangeFetches >= MAX_CONCURRENT_RANGE_FETCHES) {
+ await new Promise((res) => rangeFetchQueue.push(res));
+ }
+ activeRangeFetches++;
+ try {
+ return await fn();
+ } finally {
+ activeRangeFetches--;
+ const next = rangeFetchQueue.shift();
+ if (next) next();
+ }
+}
+
+// Unstable-connection handling. A range GET is idempotent and If-Range
+// guards consistency, so transient failures (network drops, 5xx/429, and
+// stalls -- a response that stops delivering bytes) are retried with
+// exponential backoff. Errors that retrying cannot fix (4xx, a changed
+// validator) are marked err.permanent at their throw site and rethrown
+// immediately; the degrade-to-full signal passes through untouched.
+// Exported so tests (and unusual deployments) can tune it.
+export const httpRetryConfig = {
+ retries: 3, // extra attempts after the first
+ backoffMs: 300, // doubled per retry
+ stallTimeoutMs: 10_000, // abort when no bytes (or headers) arrive for this long
+};
+
+const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
+
+async function httpReadRangeInto(url, validator, dst, dstOffset, pos, len) {
+ return withRangeFetchSlot(async () => {
+ for (let attempt = 0; ; attempt++) {
+ try {
+ return await httpReadRangeIntoOnce(url, validator, dst, dstOffset, pos, len);
+ } catch (err) {
+ if (err && (err.degradeToFull || err.permanent)) throw err;
+ if (attempt >= httpRetryConfig.retries) throw err;
+ await sleep(httpRetryConfig.backoffMs * (1 << attempt));
+ }
+ }
+ });
+}
+
+async function httpReadRangeIntoOnce(url, validator, dst, dstOffset, pos, len) {
+ const headers = { "Range": "bytes=" + pos + "-" + (pos + len - 1) };
+ if (validator) headers["If-Range"] = validator;
+ // Stall watchdog: abort when neither headers nor body bytes arrive for
+ // stallTimeoutMs. Without it a wedged connection hangs the read forever
+ // (fetch has no timeout of its own); with it, the retry loop above turns
+ // a stall into a bounded delay.
+ const ctrl = typeof AbortController !== "undefined" ? new AbortController() : null;
+ let stallTimer = null;
+ const bumpStall = () => {
+ if (!ctrl) return;
+ if (stallTimer) clearTimeout(stallTimer);
+ stallTimer = setTimeout(
+ () => ctrl.abort(new Error(url + ": no data for " + httpRetryConfig.stallTimeoutMs + "ms")),
+ httpRetryConfig.stallTimeoutMs);
+ };
+ const clearStall = () => { if (stallTimer) clearTimeout(stallTimer); stallTimer = null; };
+ bumpStall();
+ let res;
+ try {
+ res = await fetch(url, ctrl ? { headers: headers, signal: ctrl.signal } : { headers: headers });
+ } catch (err) {
+ clearStall();
+ throw err;
+ }
+ bumpStall();
+ if (res.status === 200) {
+ // A 200 mid-session means the origin does not honor Range (the 206
+ // probe answer may have come from a browser cache). If the strong
+ // validator still matches -- or we never had one -- the file is
+ // unchanged: hand the full body to the caller to degrade to
+ // buffered mode. Only a changed validator is a hard error.
+ const nowValidator = strongValidator(res);
+ if (!validator || (nowValidator && nowValidator === validator)) {
+ clearStall();
+ const degrade = new Error(url + ": origin ignored Range; degrading to full buffering");
+ degrade.degradeToFull = true;
+ degrade.fullBodyPromise = res.arrayBuffer().then((b) => new Uint8Array(b));
+ throw degrade;
+ }
+ clearStall();
+ await abandonBody(res);
+ const changed = new Error(url + ": file changed (or server stopped honoring Range) while reading");
+ changed.permanent = true; // retrying cannot bring the old bytes back
+ throw changed;
+ }
+ if (res.status !== 206) {
+ clearStall();
+ await abandonBody(res);
+ const httpErr = new Error("HTTP " + res.status + " reading range " + pos + "+" + len + " of " + url);
+ // 5xx and 429 are transient by definition; other 4xx will not change
+ if (res.status < 500 && res.status !== 429) httpErr.permanent = true;
+ throw httpErr;
+ }
+ const contentRange = res.headers.get("content-range");
+ const m = contentRange ? /bytes\s+(\d+)-(\d+)\//.exec(contentRange) : null;
+ if (m && parseInt(m[1]) !== pos) {
+ await abandonBody(res);
+ throw new Error(url + ": server returned range starting at " + m[1] + ", requested " + pos);
+ }
+
+ // Stream the body straight into the destination (typed array or
+ // BigBuffer -- both expose .set(chunk, offset)); avoids materializing
+ // a second full-size copy of large section reads.
+ let done = 0;
+ try {
+ if (res.body && typeof res.body.getReader === "function") {
+ const reader = res.body.getReader();
+ for (;;) {
+ const it = await reader.read();
+ bumpStall();
+ if (it.done) break;
+ if (done + it.value.byteLength > len) {
+ reader.cancel().catch(function () {});
+ throw new Error(url + ": range response longer than requested");
+ }
+ dst.set(it.value, dstOffset + done);
+ done += it.value.byteLength;
+ }
+ } else {
+ // coverage: fetch implementations without a streaming body (older
+ // browser polyfills); Node's undici always streams
+ /* c8 ignore start */
+ const buff = new Uint8Array(await res.arrayBuffer());
+ if (buff.byteLength > len) throw new Error(url + ": range response longer than requested");
+ dst.set(buff, dstOffset);
+ done = buff.byteLength;
+ /* c8 ignore stop */
+ }
+ } finally {
+ clearStall();
+ }
+ if (done !== len) {
+ throw new Error(url + ": short range response (" + done + "/" + len + " bytes at " + pos + ")");
+ }
+}
+
+async function abandonBody(res) {
+ try {
+ if (res.body && typeof res.body.cancel === "function") await res.body.cancel();
+ /* c8 ignore next -- non-streaming fetch polyfills only */
+ else await res.arrayBuffer();
+ } catch (e) { /* body teardown is best-effort */ }
+}
diff --git a/src/idbcache.js b/src/idbcache.js
new file mode 100644
index 0000000..caf6551
--- /dev/null
+++ b/src/idbcache.js
@@ -0,0 +1,332 @@
+// IndexedDB-backed persistent block cache for positioned range readers.
+//
+// Wraps a `readRangeInto(dst, dstOffset, pos, len)` function (the http
+// backend's reader) so that fetched bytes persist across page loads: a
+// second proving session against the same URL serves its reads from
+// IndexedDB instead of the network ("warm start"), while keeping every
+// property of the streaming design -- the standard single-file format, and
+// bounded memory (reads land directly in the caller's buffer; the cache
+// only ever allocates up to two extra blocks for the request boundaries).
+//
+// Identity and consistency: entries are keyed by URL and stamped with the
+// file's strong validator (ETag / Last-Modified) and total size. A changed
+// validator or size drops the stale blocks at open. Without a strong
+// validator the wrapper refuses to cache and returns the reader unchanged --
+// a URL-only identity could silently serve bytes of a replaced file.
+//
+// Storage layout (one shared database):
+// files: fileKey -> { validator, totalSize, blockSize, bytes, lastUsed }
+// blocks: [fileKey, blockIndex] -> Uint8Array (blockSize, tail may be short)
+//
+// Eviction is per-file LRU, applied at open: when the sum of cached bytes
+// exceeds maxBytes, least-recently-opened files are dropped (never the one
+// being opened). A zkey is useful as a whole or not at all, so file
+// granularity beats block granularity here.
+//
+// Prototype limitations (documented, deliberate):
+// - concurrent readers of the same cold block both fetch it (last write
+// wins; bytes are identical by the validator guard);
+// - the 206-unknown-total and 416 fallbacks are not persisted; the
+// streaming path and the Range-less 200 path both populate the cache
+// (the latter via persistFullBody + conditional 304 probes);
+// - eviction only runs at open, not while a session writes new blocks.
+
+const DEFAULT_BLOCK_SIZE = 1 << 21; // 2 MiB: amortizes IDB per-op cost
+const DEFAULT_MAX_BYTES = 1 << 29; // 512 MiB across all cached files
+const DEFAULT_DB_NAME = "fastfile-http-cache";
+
+const dbConnections = new Map(); // dbName -> Promise
+
+function openDb(dbName) {
+ if (dbConnections.has(dbName)) return dbConnections.get(dbName);
+ const p = new Promise((resolve, reject) => {
+ const req = indexedDB.open(dbName, 1);
+ req.onupgradeneeded = () => {
+ const db = req.result;
+ db.createObjectStore("files");
+ db.createObjectStore("blocks");
+ };
+ req.onsuccess = () => resolve(req.result);
+ req.onerror = () => reject(req.error);
+ req.onblocked = () => reject(new Error("IndexedDB open blocked"));
+ });
+ dbConnections.set(dbName, p);
+ p.catch(() => dbConnections.delete(dbName));
+ return p;
+}
+
+// Small promise adapters over the IDB request API.
+function idbReq(req) {
+ return new Promise((resolve, reject) => {
+ req.onsuccess = () => resolve(req.result);
+ req.onerror = () => reject(req.error);
+ });
+}
+function txDone(tx) {
+ return new Promise((resolve, reject) => {
+ tx.oncomplete = () => resolve();
+ tx.onerror = () => reject(tx.error);
+ tx.onabort = () => reject(tx.error || new Error("IndexedDB transaction aborted"));
+ });
+}
+
+function blockRange(fileKey, from, to) {
+ return IDBKeyRange.bound([fileKey, from], [fileKey, to]);
+}
+
+async function deleteFileEntries(db, fileKey) {
+ const tx = db.transaction(["files", "blocks"], "readwrite");
+ tx.objectStore("files").delete(fileKey);
+ tx.objectStore("blocks").delete(blockRange(fileKey, 0, Infinity));
+ await txDone(tx);
+}
+
+// Register the file, invalidate stale blocks, apply LRU eviction.
+async function prepareFile(db, fileKey, validator, totalSize, blockSize, maxBytes) {
+ const tx = db.transaction(["files", "blocks"], "readwrite");
+ const files = tx.objectStore("files");
+ const existing = await idbReq(files.get(fileKey));
+ let bytes = 0;
+ if (existing &&
+ existing.validator === validator &&
+ existing.totalSize === totalSize &&
+ existing.blockSize === blockSize) {
+ bytes = existing.bytes;
+ } else if (existing) {
+ // stale: same URL, different content or geometry
+ tx.objectStore("blocks").delete(blockRange(fileKey, 0, Infinity));
+ }
+ files.put({ validator, totalSize, blockSize, bytes, lastUsed: Date.now() }, fileKey);
+ await txDone(tx);
+
+ // LRU eviction across files (never the one just opened).
+ const rtx = db.transaction("files", "readonly");
+ const store = rtx.objectStore("files");
+ const [keys, metas] = await Promise.all([idbReq(store.getAllKeys()), idbReq(store.getAll())]);
+ await txDone(rtx);
+ let total = metas.reduce((s, mm) => s + mm.bytes, 0);
+ if (total <= maxBytes) return;
+ const victims = keys.map((k, i) => ({ key: k, meta: metas[i] }))
+ .filter((f) => f.key !== fileKey)
+ .sort((a, b) => a.meta.lastUsed - b.meta.lastUsed);
+ for (const v of victims) {
+ if (total <= maxBytes) break;
+ await deleteFileEntries(db, v.key);
+ total -= v.meta.bytes;
+ }
+}
+
+// Wrap `readRangeInto` with the persistent cache. Returns the original
+// reader unchanged when caching is impossible (no IndexedDB in this
+// environment, storage blocked, or no strong validator to key on).
+export async function wrapWithPersistentCache(readRangeInto, o) {
+ const { fileKey, validator, totalSize } = o;
+ const opts = (typeof o.options === "object" && o.options) || {};
+ const blockSize = opts.blockSize || DEFAULT_BLOCK_SIZE;
+ const maxBytes = opts.maxBytes || DEFAULT_MAX_BYTES;
+ const dbName = opts.dbName || DEFAULT_DB_NAME;
+
+ if (typeof indexedDB === "undefined" || !validator) return readRangeInto;
+ let db;
+ try {
+ db = await openDb(dbName);
+ await prepareFile(db, fileKey, validator, totalSize, blockSize, maxBytes);
+ } catch (e) {
+ // Private windows, blocked site data, quota pressure at open: the
+ // cache is a convenience, never a requirement.
+ return readRangeInto;
+ }
+
+ let broken = false; // a failed write disables persistence, not reads
+
+ async function loadCached(firstBlock, lastBlock) {
+ const tx = db.transaction("blocks", "readonly");
+ const store = tx.objectStore("blocks");
+ const range = blockRange(fileKey, firstBlock, lastBlock);
+ const [keys, values] = await Promise.all([idbReq(store.getAllKeys(range)), idbReq(store.getAll(range))]);
+ await txDone(tx);
+ const found = new Map();
+ for (let i = 0; i < keys.length; i++) found.set(keys[i][1], values[i]);
+ return found;
+ }
+
+ async function persistBlocks(entries) { // [{index, data}] with data copied already
+ if (broken || entries.length === 0) return;
+ try {
+ const tx = db.transaction(["files", "blocks"], "readwrite");
+ const blocks = tx.objectStore("blocks");
+ const files = tx.objectStore("files");
+ for (const e of entries) blocks.put(e.data, [fileKey, e.index]);
+ const meta = await idbReq(files.get(fileKey));
+ /* c8 ignore next -- meta vanishes only if another tab evicts mid-session */
+ if (meta) {
+ meta.bytes += entries.reduce((s, e) => s + e.data.byteLength, 0);
+ meta.lastUsed = Date.now();
+ files.put(meta, fileKey);
+ }
+ await txDone(tx);
+ } catch (e) {
+ broken = true; // quota exceeded etc.: keep reading, stop writing
+ }
+ }
+
+ const blockLen = (index) =>
+ Math.min(blockSize, totalSize - index * blockSize);
+
+ // In-flight dedupe: provers issue concurrent, overlapping reads (MSM
+ // read-ahead, coefficient streaming), and without this every concurrent
+ // miss of the same block refetched it -- measured 3.3x the zkey size on
+ // the wire for a cold authV3 proof. A missing block gets one fetch; every
+ // other reader awaits its promise.
+ const inFlight = new Map(); // blockIndex -> Promise
+ function deferBlock(index) {
+ let resolve, reject;
+ const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
+ promise.catch(() => {}); // waiters handle it; avoid unhandled-rejection noise
+ inFlight.set(index, promise);
+ return { resolve, reject, promise };
+ }
+
+ return async function cachedReadRangeInto(dst, dstOffset, pos, len) {
+ if (len === 0) return;
+ const firstBlock = Math.floor(pos / blockSize);
+ const lastBlock = Math.floor((pos + len - 1) / blockSize);
+ const found = await loadCached(firstBlock, lastBlock);
+
+ const toPersist = [];
+ const copyInto = (block, i) => {
+ const bStart = i * blockSize;
+ const from = Math.max(pos, bStart);
+ const to = Math.min(pos + len, bStart + blockLen(i));
+ dst.set(block.subarray(from - bStart, to - bStart), dstOffset + (from - pos));
+ };
+ // Walk the block range, serving hits (cached or in-flight) and
+ // grouping misses into runs of blocks that lie fully inside the
+ // request (fetched directly into dst, no extra copy) -- boundary
+ // blocks that stick out past the request are fetched whole into a
+ // one-block temp so the cache always stores complete blocks.
+ let i = firstBlock;
+ while (i <= lastBlock) {
+ const bStart = i * blockSize;
+ const bEnd = bStart + blockLen(i);
+ const hit = found.get(i);
+ if (hit) {
+ copyInto(hit, i);
+ i++;
+ continue;
+ }
+ const pending = inFlight.get(i);
+ if (pending) {
+ copyInto(await pending, i);
+ i++;
+ continue;
+ }
+ if (bStart >= pos && bEnd <= pos + len) {
+ // interior run: extend over consecutive interior misses
+ let j = i;
+ while (j + 1 <= lastBlock && !found.get(j + 1) && !inFlight.get(j + 1) &&
+ (j + 1) * blockSize + blockLen(j + 1) <= pos + len) j++;
+ const runStart = bStart;
+ const runEnd = j * blockSize + blockLen(j);
+ const defers = [];
+ for (let b = i; b <= j; b++) defers.push(deferBlock(b));
+ try {
+ await readRangeInto(dst, dstOffset + (runStart - pos), runStart, runEnd - runStart);
+ } catch (err) {
+ for (let b = i; b <= j; b++) { defers[b - i].reject(err); inFlight.delete(b); }
+ throw err;
+ }
+ for (let b = i; b <= j; b++) {
+ const s = b * blockSize;
+ const data = dst.slice(dstOffset + (s - pos), dstOffset + (s - pos) + blockLen(b));
+ defers[b - i].resolve(data);
+ toPersist.push({ index: b, data });
+ }
+ i = j + 1;
+ } else {
+ // boundary block partially outside the request: fetch it
+ // whole so the stored block is complete
+ const defer = deferBlock(i);
+ const block = new Uint8Array(blockLen(i));
+ try {
+ await readRangeInto(block, 0, bStart, block.length);
+ } catch (err) {
+ defer.reject(err);
+ inFlight.delete(i);
+ throw err;
+ }
+ defer.resolve(block);
+ copyInto(block, i);
+ toPersist.push({ index: i, data: block });
+ i++;
+ }
+ }
+ await persistBlocks(toPersist);
+ // keep resolved blocks discoverable until they are persisted, then
+ // let waiters fall through to IndexedDB
+ for (const e of toPersist) inFlight.delete(e.index);
+ };
+}
+
+// Peek at what the cache knows about a URL before any network request.
+// Returns { validator, totalSize, blockSize, bytes } or null. Used to send a
+// conditional probe (If-None-Match / If-Modified-Since): an unchanged file
+// answers 304 with no body, which is what makes warm starts work even
+// against servers that ignore Range and would otherwise ship the whole file
+// in the probe response.
+export async function peekPersistentMeta(o) {
+ const opts = (typeof o.options === "object" && o.options) || {};
+ const dbName = opts.dbName || DEFAULT_DB_NAME;
+ if (typeof indexedDB === "undefined") return null;
+ try {
+ const db = await openDb(dbName);
+ const tx = db.transaction("files", "readonly");
+ const meta = await idbReq(tx.objectStore("files").get(o.fileKey));
+ await txDone(tx);
+ return meta ? { validator: meta.validator, totalSize: meta.totalSize, blockSize: meta.blockSize, bytes: meta.bytes } : null;
+ } catch (e) {
+ return null;
+ }
+}
+
+// Persist a fully-downloaded body (the Range-less server path) so the next
+// session can warm-start from it. Blocks are written in bounded batches;
+// meta.bytes is set to the exact total afterwards (overwrites make
+// incremental accounting drift). Best-effort: returns false when the
+// environment has no usable IndexedDB or a write fails.
+export async function persistFullBody(o) {
+ const { fileKey, validator, totalSize, data } = o;
+ const opts = (typeof o.options === "object" && o.options) || {};
+ const blockSize = opts.blockSize || DEFAULT_BLOCK_SIZE;
+ const maxBytes = opts.maxBytes || DEFAULT_MAX_BYTES;
+ const dbName = opts.dbName || DEFAULT_DB_NAME;
+ if (typeof indexedDB === "undefined" || !validator) return false;
+ try {
+ const db = await openDb(dbName);
+ await prepareFile(db, fileKey, validator, totalSize, blockSize, maxBytes);
+ const nBlocks = Math.ceil(totalSize / blockSize);
+ const BATCH = 64;
+ for (let b0 = 0; b0 < nBlocks; b0 += BATCH) {
+ const tx = db.transaction("blocks", "readwrite");
+ const blocks = tx.objectStore("blocks");
+ for (let b = b0; b < Math.min(b0 + BATCH, nBlocks); b++) {
+ const s = b * blockSize;
+ blocks.put(data.slice(s, Math.min(s + blockSize, totalSize)), [fileKey, b]);
+ }
+ await txDone(tx);
+ }
+ const tx = db.transaction("files", "readwrite");
+ const files = tx.objectStore("files");
+ const meta = await idbReq(files.get(fileKey));
+ /* c8 ignore else -- meta vanishes only if another tab evicts mid-write */
+ if (meta) {
+ meta.bytes = totalSize;
+ meta.lastUsed = Date.now();
+ files.put(meta, fileKey);
+ }
+ await txDone(tx);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
diff --git a/src/memfile.js b/src/memfile.js
index fa74a7d..5b13aab 100644
--- a/src/memfile.js
+++ b/src/memfile.js
@@ -162,11 +162,14 @@ class MemFile {
let currentPosition = typeof pos == "undefined" ? self.pos : pos;
- if (currentPosition > this.totalSize) {
+ if (currentPosition >= this.totalSize) {
if (this.readOnly) {
throw new Error("Reading out of bounds");
}
- this._resizeIfNeeded(pos);
+ // Past the written data there is no string to read. (This used to
+ // grow the allocation and then build a negative-length view, which
+ // threw a RangeError.)
+ return "";
}
const dataArray = new Uint8Array(
self.o.data.buffer,
diff --git a/src/osfile.js b/src/osfile.js
index fcd8445..b2fe940 100644
--- a/src/osfile.js
+++ b/src/osfile.js
@@ -26,6 +26,12 @@ class FastFile {
this.totalSize = stats.size;
this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1;
this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1;
+ // Reads/writes at least this large bypass the page cache and move bytes
+ // straight between disk and the caller's buffer (see readToBuffer /
+ // write), avoiding the extra buffer<->page copy that dominates large
+ // sequential transfers (e.g. zkey/ptau sections).
+ this.directReadThreshold = 1 << 20;
+ this.directWriteThreshold = 1 << 20;
this.pages = {};
this.pendingLoads = [];
this.writing = false;
@@ -47,6 +53,8 @@ class FastFile {
return P;
}
+ // coverage: debug instrumentation, only enabled by hand (this.logHistory)
+ /* c8 ignore start */
__statusPage(s, p) {
const logEntry = [];
const self=this;
@@ -84,6 +92,8 @@ class FastFile {
+ /* c8 ignore stop */
+
_triggerLoad() {
const self = this;
@@ -150,7 +160,17 @@ class FastFile {
self.__statusPage("After Load (loaded): ", load.page);
return res;
}, (err) => {
- load.reject(err);
+ // Reject EVERY waiter, not just the first: co-readers of the
+ // same page were appended to page.loading (not to `load`) and
+ // would otherwise await forever. Drop the page entirely so a
+ // later retry re-reads it instead of queueing onto a dead
+ // loading list.
+ const page = self.pages[load.page];
+ const loading = (page && page.loading) ? page.loading : [load];
+ delete self.pages[load.page];
+ for (let i=0; i {
console.log("ERROR Writing: "+err);
+ // Clear `writing` (a stuck flag pins the page forever and
+ // blocks _tryClose) and record the error. write()/read()
+ // surface it on their next call (fail fast) and close()
+ // rejects with it -- previously it was only visible at
+ // close(), so a prover that skipped close on error paths
+ // silently produced a truncated/corrupt file.
+ page.writing = false;
self.error = err;
self._tryClose();
}));
@@ -226,20 +253,47 @@ class FastFile {
return -1;
}
+ // Iterate the actually-cached pages (usually few) rather than every page
+ // index in [firstPage, lastPage], so the check stays O(cached pages) even
+ // for very large ranges / small page sizes.
+ _rangeHasCachedPages(pos, len) {
+ const firstPage = Math.floor(pos / this.pageSize);
+ const lastPage = Math.floor((pos + len - 1) / this.pageSize);
+ for (const k of Object.keys(this.pages)) {
+ const p = +k;
+ if (p >= firstPage && p <= lastPage) return true;
+ }
+ return false;
+ }
+
async write(buff, pos) {
if (buff.byteLength == 0) return;
const self = this;
- /*
- if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) {
- const cacheSize = Math.floor(buff.byteLength * 1.1);
- this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1;
- }
- */
+ if (self.error) throw self.error;
if (typeof pos == "undefined") pos = self.pos;
self.pos = pos+buff.byteLength;
if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength;
if (self.pendingClose)
throw new Error("Writing a closing file");
+
+ // Direct-write fast path: for large writes to a region with no cached
+ // pages, write straight to disk, skipping the buff->page copy and the
+ // deferred page flush. Any cached page in range (even clean) would go
+ // stale after a direct write, so we fall back to the cached path then.
+ // ArrayBuffer.isView gate: fd.write needs a real TypedArray/DataView; a
+ // BigBuffer (paged, not a view) must use the cached path.
+ if (buff.byteLength >= self.directWriteThreshold && ArrayBuffer.isView(buff) && !self._rangeHasCachedPages(pos, buff.byteLength)) {
+ let done = 0;
+ while (done < buff.byteLength) {
+ const { bytesWritten } = await self.fd.write(buff, done, buff.byteLength - done, pos + done);
+ if (bytesWritten === 0) break; // should not happen
+ done += bytesWritten;
+ }
+ const lastPage = Math.floor((pos + buff.byteLength - 1) / self.pageSize);
+ if (lastPage + 1 > self.totalPages) self.totalPages = lastPage + 1;
+ return;
+ }
+
const firstPage = Math.floor(pos / self.pageSize);
const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize);
@@ -277,19 +331,56 @@ class FastFile {
return buff;
}
+ // Iterate the actually-cached pages (usually few) rather than every page
+ // index in [firstPage, lastPage], so the check stays O(cached pages) even
+ // for very large ranges / small page sizes.
+ _rangeHasDirtyPages(pos, len) {
+ const firstPage = Math.floor(pos / this.pageSize);
+ const lastPage = Math.floor((pos + len - 1) / this.pageSize);
+ for (const k of Object.keys(this.pages)) {
+ const p = +k;
+ if (p >= firstPage && p <= lastPage) {
+ const page = this.pages[p];
+ if (page.dirty || page.writing) return true;
+ }
+ }
+ return false;
+ }
+
async readToBuffer(buffDst, offset, len, pos) {
if (len == 0) {
return;
}
const self = this;
- if (len > self.pageSize*self.maxPagesLoaded*0.8) {
- const cacheSize = Math.floor(len * 1.1);
- this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1;
- }
+ if (self.error) throw self.error;
if (typeof pos == "undefined") pos = self.pos;
self.pos = pos+len;
if (self.pendingClose)
throw new Error("Reading a closing file");
+
+ // Direct-read fast path: for large reads with no overlapping unwritten
+ // (dirty) pages, copy straight from disk into the destination buffer.
+ // This skips the page cache and the page->destination copy it incurs,
+ // which dominates large sequential reads (e.g. zkey/ptau sections).
+ // ArrayBuffer.isView gate: the direct path hands buffDst to fd.read, which
+ // needs a real TypedArray/DataView. A BigBuffer (paged, not a view) must
+ // go through the cached path, which copies into it via its own .set().
+ if (len >= self.directReadThreshold && ArrayBuffer.isView(buffDst) && !self._rangeHasDirtyPages(pos, len)) {
+ let toRead = (pos + len > self.totalSize) ? (self.totalSize - pos) : len;
+ if (toRead < 0) toRead = 0;
+ let done = 0;
+ while (done < toRead) {
+ const { bytesRead } = await self.fd.read(buffDst, offset + done, toRead - done, pos + done);
+ if (bytesRead === 0) break; // EOF
+ done += bytesRead;
+ }
+ return;
+ }
+
+ if (len > self.pageSize*self.maxPagesLoaded*0.8) {
+ const cacheSize = Math.floor(len * 1.1);
+ this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1;
+ }
const firstPage = Math.floor(pos / self.pageSize);
const lastPage = Math.floor((pos + len -1) / self.pageSize);
@@ -300,8 +391,16 @@ class FastFile {
let p = firstPage;
let o = pos % self.pageSize;
- // Remaining bytes to read
+ // Remaining bytes to read (clamped to EOF: a read past the end of a
+ // truncated/short file reads fewer bytes than requested).
let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len;
+ // Bytes already written to buffDst -- tracked independently of `r`
+ // (which shrinks on EOF-clamping) so the destination offset stays
+ // correct. Previously computed as `offset + len - r`: with `r`
+ // pre-clamped below `len`, that put the first bytes read at a
+ // nonzero offset instead of the real EOF-truncated tail, silently
+ // shifting valid data to the wrong position in the output buffer.
+ let done = 0;
while (r>0) {
await pagePromises[p - firstPage];
self.__statusPage("After Await (read): ", p);
@@ -309,12 +408,13 @@ class FastFile {
// bytes to copy from this page
const l = (o+r > self.pageSize) ? (self.pageSize -o) : r;
const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l);
- buffDst.set(srcView, offset+len-r);
+ buffDst.set(srcView, offset+done);
self.pages[p].pendingOps --;
self.__statusPage("After Op done: ", p);
r = r-l;
+ done = done+l;
p ++;
o = 0;
if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self));
@@ -330,6 +430,7 @@ class FastFile {
if (!self.pendingClose) return;
if (self.error) {
self.pendingCloseReject(self.error);
+ return;
}
const p = self._getDirtyPage();
if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return;
@@ -338,9 +439,11 @@ class FastFile {
close() {
const self = this;
- if (self.pendingClose)
- throw new Error("Closing the file twice");
- return new Promise((resolve, reject) => {
+ // Idempotent, matching fs.promises.FileHandle.close(): repeated calls
+ // return the same promise, so cleanup code (e.g. a finally block) can
+ // close unconditionally. Reads/writes after close still throw.
+ if (self.closePromise) return self.closePromise;
+ self.closePromise = new Promise((resolve, reject) => {
self.pendingClose = resolve;
self.pendingCloseReject = reject;
self._tryClose();
@@ -350,6 +453,7 @@ class FastFile {
self.fd.close();
throw (err);
});
+ return self.closePromise;
}
async discard() {
diff --git a/src/rangefile.js b/src/rangefile.js
new file mode 100644
index 0000000..36b8942
--- /dev/null
+++ b/src/rangefile.js
@@ -0,0 +1,182 @@
+// Shared read-only file over an abstract positioned range reader.
+//
+// Backends (httpfile, blobfile) supply a single primitive:
+// readRangeInto(dstBuff, dstOffset, pos, len) -> Promise
+// and this class layers the FastFile read interface on top:
+// - reads >= pageSize bypass the cache and go straight to the backend
+// (the file is read-only, so a direct read is always coherent);
+// - smaller reads (header scans: magics, section tables, ULE32/64) are
+// served from page-aligned cached ranges so that e.g. a binfile section
+// scan does not issue one backend request per 4-byte field.
+//
+// Write operations throw: remote ranges are strictly a read transport.
+
+const DEFAULT_CACHE_SIZE = 1 << 20;
+const DEFAULT_PAGE_SIZE = 1 << 13;
+
+export class RangeFile {
+
+ constructor(readRangeInto, totalSize, cacheSize, pageSize) {
+ this.readRangeInto = readRangeInto;
+ this.totalSize = totalSize;
+ this.pos = 0;
+ this.pageSize = pageSize || DEFAULT_PAGE_SIZE;
+ this.maxPagesLoaded = Math.floor((cacheSize || DEFAULT_CACHE_SIZE) / this.pageSize) + 1;
+ this.pages = new Map(); // page index -> { buff: Uint8Array|null, promise: Promise }
+ this.readOnly = true;
+ }
+
+ _pageLen(p) {
+ const start = p * this.pageSize;
+ const end = Math.min(start + this.pageSize, this.totalSize);
+ return end - start;
+ }
+
+ // Load (or join the in-flight load of) page p; resolves to its buffer.
+ // A failed load removes the entry so a later retry re-requests it.
+ _loadPage(p) {
+ const self = this;
+ let page = self.pages.get(p);
+ if (page) {
+ // LRU touch: re-insert so Map iteration order tracks recency.
+ self.pages.delete(p);
+ self.pages.set(p, page);
+ return page.promise;
+ }
+ const buff = new Uint8Array(self._pageLen(p));
+ page = { buff: null, promise: null };
+ page.promise = self.readRangeInto(buff, 0, p * self.pageSize, buff.byteLength).then(function () {
+ page.buff = buff;
+ return buff;
+ }, function (err) {
+ self.pages.delete(p);
+ throw err;
+ });
+ self.pages.set(p, page);
+ self._trimCache();
+ return page.promise;
+ }
+
+ _trimCache() {
+ const self = this;
+ if (self.pages.size <= self.maxPagesLoaded) return;
+ // Evict oldest settled pages first; in-flight loads are kept.
+ for (const entry of self.pages) {
+ if (self.pages.size <= self.maxPagesLoaded) return;
+ if (entry[1].buff) self.pages.delete(entry[0]);
+ }
+ }
+
+ async readToBuffer(buffDst, offset, len, pos) {
+ const self = this;
+ if (len === 0) return;
+ if (self.pendingClose) throw new Error("Reading a closing file");
+ if (typeof pos === "undefined") pos = self.pos;
+ if (pos + len > self.totalSize) throw new Error("Reading out of bounds");
+ self.pos = pos + len;
+
+ // Direct path: one backend request straight into the destination
+ // (works for both typed arrays and BigBuffer via .set()).
+ if (len >= self.pageSize) {
+ await self.readRangeInto(buffDst, offset, pos, len);
+ return;
+ }
+
+ const firstPage = Math.floor(pos / self.pageSize);
+ const lastPage = Math.floor((pos + len - 1) / self.pageSize);
+ let o = pos % self.pageSize;
+ let done = 0;
+ for (let p = firstPage; p <= lastPage; p++) {
+ const buff = await self._loadPage(p);
+ const l = Math.min(len - done, self.pageSize - o);
+ buffDst.set(buff.subarray(o, o + l), offset + done);
+ done += l;
+ o = 0;
+ }
+ }
+
+ async read(len, pos) {
+ const buff = new Uint8Array(len);
+ await this.readToBuffer(buff, 0, len, pos);
+ return buff;
+ }
+
+ async readULE32(pos) {
+ const b = await this.read(4, pos);
+ const view = new Uint32Array(b.buffer);
+ return view[0];
+ }
+
+ async readUBE32(pos) {
+ const b = await this.read(4, pos);
+ const view = new DataView(b.buffer);
+ return view.getUint32(0, false);
+ }
+
+ async readULE64(pos) {
+ const b = await this.read(8, pos);
+ const view = new Uint32Array(b.buffer);
+ return view[1] * 0x100000000 + view[0];
+ }
+
+ async readString(pos) {
+ const self = this;
+ if (self.pendingClose) throw new Error("Reading a closing file");
+ let p = typeof pos === "undefined" ? self.pos : pos;
+ const chunks = [];
+ while (p < self.totalSize) {
+ const l = Math.min(self.pageSize, self.totalSize - p);
+ const chunk = await self.read(l, p);
+ const z = chunk.indexOf(0);
+ if (z >= 0) {
+ chunks.push(chunk.subarray(0, z));
+ self.pos = p + z + 1;
+ return decodeChunks(chunks);
+ }
+ chunks.push(chunk);
+ p += l;
+ }
+ // No terminator before EOF: the string ends at EOF.
+ self.pos = p;
+ return decodeChunks(chunks);
+ }
+
+ async write() {
+ throw new Error("Writing a read only file");
+ }
+
+ async writeULE32() {
+ throw new Error("Writing a read only file");
+ }
+
+ async writeUBE32() {
+ throw new Error("Writing a read only file");
+ }
+
+ async writeULE64() {
+ throw new Error("Writing a read only file");
+ }
+
+ async close() {
+ // Idempotent: a second close is a no-op, matching the os backend.
+ if (this.pendingClose) return;
+ this.pendingClose = true;
+ this.pages.clear();
+ }
+
+ async discard() {
+ await this.close();
+ }
+}
+
+function decodeChunks(chunks) {
+ let total = 0;
+ for (let i = 0; i < chunks.length; i++) total += chunks[i].byteLength;
+ const all = new Uint8Array(total);
+ let o = 0;
+ for (let i = 0; i < chunks.length; i++) {
+ all.set(chunks[i], o);
+ o += chunks[i].byteLength;
+ }
+ return new TextDecoder().decode(all);
+}
diff --git a/test/api_surface.test.js b/test/api_surface.test.js
new file mode 100644
index 0000000..12b12b8
--- /dev/null
+++ b/test/api_surface.test.js
@@ -0,0 +1,519 @@
+import fs from "fs";
+import http from "http";
+import * as fastFile from "../src/fastfile.js";
+
+import assert from "assert";
+import { expect } from "vitest";
+
+
+// Behavioral coverage of the full FastFile API surface: the dispatcher
+// variants in fastfile.js, and the ULE/UBE/string helpers plus error paths
+// of every backend (mem, bigMem, os, http/range, blob).
+
+const BIGMEM_PAGE = 1 << 22; // bigmemfile's fixed page size
+
+function makeData(n) {
+ const data = new Uint8Array(n);
+ for (let i = 0; i < n; i++) data[i] = (i * 7 + 3) & 0xFF;
+ return data;
+}
+
+// Round-trips every numeric helper plus a string on a writable fd.
+async function roundTripHelpers(fd) {
+ await fd.writeULE32(0x01020304, 0);
+ await fd.writeUBE32(0x0A0B0C0D, 4);
+ await fd.writeULE64(0x1FFFFFFFFF, 8); // > 2^32: exercises the high word
+
+ assert.strictEqual(await fd.readULE32(0), 0x01020304);
+ assert.strictEqual(await fd.readUBE32(4), 0x0A0B0C0D);
+ assert.strictEqual(await fd.readULE64(8), 0x1FFFFFFFFF);
+
+ // byte-level check of endianness
+ const raw = await fd.read(8, 0);
+ assert.deepStrictEqual([...raw], [4, 3, 2, 1, 0x0A, 0x0B, 0x0C, 0x0D]);
+}
+
+describe("fastfile API surface", function () {
+
+ describe("dispatcher (fastfile.js)", function () {
+ it("createOverride / createNoOverride / readWriteExisting reject unknown types", async () => {
+ await expect(fastFile.createOverride({ type: "nope" })).rejects.toThrow("Invalid FastFile type");
+ expect(() => fastFile.createNoOverride({ type: "nope" })).to.throw("Invalid FastFile type");
+ await expect(fastFile.readExisting({ type: "nope" })).rejects.toThrow("Invalid FastFile type");
+ expect(() => fastFile.readWriteExisting({ type: "nope" })).to.throw("Invalid FastFile type");
+ expect(() => fastFile.readWriteExistingOrCreate({ type: "nope" })).to.throw("Invalid FastFile type");
+ });
+
+ it("createNoOverride creates mem/bigMem files and a fresh os file, but refuses an existing one", async () => {
+ const mem = fastFile.createNoOverride({ type: "mem" });
+ await mem.write(new Uint8Array([1, 2]), 0);
+ mem.close();
+
+ const big = fastFile.createNoOverride({ type: "bigMem" });
+ await big.write(new Uint8Array([1, 2]), 0);
+ big.close();
+
+ const fileName = "test_no_override.bin";
+ const fd = await fastFile.createNoOverride(fileName);
+ await fd.write(new Uint8Array([9]), 0);
+ await fd.close();
+ // O_EXCL: a second createNoOverride on the same path must fail
+ await expect(fastFile.createNoOverride(fileName)).rejects.toThrow();
+ await fs.promises.unlink(fileName);
+ });
+
+ it("readWriteExisting opens mem, bigMem and os files for update", async () => {
+ const memData = { type: "mem", data: makeData(16) };
+ const mem = fastFile.readWriteExisting(memData);
+ await mem.write(new Uint8Array([0xFF]), 0);
+ assert.strictEqual((await mem.read(1, 0))[0], 0xFF);
+ mem.close();
+
+ const big = fastFile.readWriteExisting({ type: "bigMem", data: [makeData(16)] });
+ await big.write(new Uint8Array([0xEE]), 0);
+ assert.strictEqual((await big.read(1, 0))[0], 0xEE);
+ big.close();
+
+ const fileName = "test_rw_existing.bin";
+ await fs.promises.writeFile(fileName, Buffer.from(makeData(32)));
+ const fd = await fastFile.readWriteExisting(fileName);
+ await fd.write(new Uint8Array([0xAB]), 0);
+ assert.strictEqual((await fd.read(1, 0))[0], 0xAB);
+ await fd.close();
+ await fs.promises.unlink(fileName);
+ });
+
+ it("readWriteExistingOrCreate creates a fresh os file and opens mem/bigMem", async () => {
+ const fileName = "test_rw_or_create.bin";
+ const fd = await fastFile.readWriteExistingOrCreate(fileName);
+ await fd.write(new Uint8Array([1, 2, 3]), 0);
+ await fd.close();
+ assert.strictEqual((await fs.promises.stat(fileName)).size, 3);
+ await fs.promises.unlink(fileName);
+
+ const mem = fastFile.readWriteExistingOrCreate({ type: "mem", data: makeData(4) });
+ assert.strictEqual(mem.totalSize, 4);
+ mem.close();
+
+ const big = fastFile.readWriteExistingOrCreate({ type: "bigMem", data: [makeData(4)] });
+ assert.strictEqual(big.totalSize, 4);
+ big.close();
+ });
+
+ it("readExisting accepts a bare Uint8Array and a bigMem descriptor", async () => {
+ const data = makeData(8);
+ const fd = await fastFile.readExisting(data);
+ assert.deepStrictEqual([...(await fd.read(8, 0))], [...data]);
+ fd.close();
+
+ const big = await fastFile.readExisting({ type: "bigMem", data: [makeData(8)] });
+ assert.strictEqual(big.totalSize, 8);
+ assert.strictEqual(big.readOnly, true);
+ big.close();
+ });
+ });
+
+ describe("mem backend", function () {
+ it("round-trips the numeric helpers", async () => {
+ const fd = await fastFile.createOverride({ type: "mem" });
+ await roundTripHelpers(fd);
+ fd.close();
+ });
+
+ it("grows the allocation when writing beyond it, and trims on close", async () => {
+ const o = { type: "mem", initialSize: 4 };
+ const fd = await fastFile.createOverride(o);
+ const big = makeData(1 << 21); // 2 MiB: beyond the 1 MiB growth step
+ await fd.write(big, 0);
+ assert.strictEqual(fd.totalSize, big.byteLength);
+ fd.close();
+ assert.strictEqual(o.data.byteLength, big.byteLength);
+ // a second close finds byteLength == totalSize and does not re-trim
+ fd.close();
+ });
+
+ it("readToBuffer beyond the end grows a writable file but rejects on a read-only one", async () => {
+ const rw = fastFile.readWriteExisting({ type: "mem", data: makeData(4) });
+ const got = await rw.read(8, 0); // grows to 8; tail is zero-filled
+ assert.deepStrictEqual([...got.slice(4)], [0, 0, 0, 0]);
+
+ const ro = await fastFile.readExisting({ type: "mem", data: makeData(4) });
+ await expect(ro.read(8, 0)).rejects.toThrow("Reading out of bounds");
+ await expect(ro.write(new Uint8Array(1), 0)).rejects.toThrow("read only");
+ });
+
+ it("readString finds terminated strings and returns empty when unterminated", async () => {
+ const enc = new TextEncoder();
+ const fd = await fastFile.createOverride({ type: "mem" });
+ await fd.write(enc.encode("hello"), 0);
+ await fd.write(new Uint8Array([0]), 5);
+ await fd.write(enc.encode("tail"), 6); // no terminator
+
+ assert.strictEqual(await fd.readString(0), "hello");
+ // sequential read continues after the terminator: unterminated tail
+ const tail = await fd.readString();
+ assert.strictEqual(tail, "");
+
+ // read-only fd: reading a string past the end rejects
+ const ro = await fastFile.readExisting({ type: "mem", data: enc.encode("x") });
+ await expect(ro.readString(10)).rejects.toThrow("Reading out of bounds");
+
+ // writable fd: a position past the end resizes and yields ""
+ assert.strictEqual(await fd.readString(1000), "");
+
+ await fd.discard();
+ fd.close();
+ });
+ });
+
+ describe("bigMem backend", function () {
+ it("preallocates pages for initialSize and round-trips the numeric helpers", async () => {
+ const fd = await fastFile.createOverride({ type: "bigMem", initialSize: BIGMEM_PAGE + 10 });
+ assert.strictEqual(fd.o.data.length, 2);
+ await roundTripHelpers(fd);
+ await fd.discard();
+ fd.close();
+ });
+
+ it("writes and reads across the page boundary", async () => {
+ const fd = await fastFile.createOverride({ type: "bigMem" });
+ const chunk = makeData(4096);
+ const pos = BIGMEM_PAGE - 100; // straddles pages 0 and 1
+ await fd.write(chunk, pos);
+ const got = await fd.read(4096, pos);
+ assert.deepStrictEqual([...got], [...chunk]);
+ assert.strictEqual(fd.o.data.length, 2);
+ fd.close();
+ });
+
+ it("read-only files reject out-of-bounds reads and writes", async () => {
+ const fd = await fastFile.readExisting({ type: "bigMem", data: [makeData(16)] });
+ await expect(fd.read(32, 0)).rejects.toThrow();
+ await expect(fd.write(new Uint8Array(1), 0)).rejects.toThrow("read only");
+ });
+
+ it("readString handles long strings, page boundaries and a missing terminator", async () => {
+ const enc = new TextEncoder();
+ const fd = await fastFile.createOverride({ type: "bigMem" });
+
+ // longer than the 2048-byte scan chunk
+ const long = "a".repeat(5000);
+ await fd.write(enc.encode(long), 0);
+ await fd.write(new Uint8Array([0]), 5000);
+ assert.strictEqual(await fd.readString(0), long);
+
+ // string crossing the 4 MiB page boundary
+ const cross = "b".repeat(200);
+ await fd.write(enc.encode(cross), BIGMEM_PAGE - 100);
+ await fd.write(new Uint8Array([0]), BIGMEM_PAGE + 100);
+ assert.strictEqual(await fd.readString(BIGMEM_PAGE - 100), cross);
+
+ // unterminated string: ends at EOF instead of spinning forever
+ const fd2 = await fastFile.createOverride({ type: "bigMem" });
+ await fd2.write(enc.encode("no-end"), 0);
+ assert.strictEqual(await fd2.readString(0), "no-end");
+ fd2.close();
+
+ fd.close();
+ });
+
+ it("readString past the end of a writable file yields the empty string or ERROR at a page boundary", async () => {
+ const fd = await fastFile.createOverride({ type: "bigMem" });
+ await fd.write(new Uint8Array([1, 2, 3]), 0);
+ assert.strictEqual(await fd.readString(100), "");
+ // exactly at a page boundary the resized data has no next page
+ await expect(fd.readString(BIGMEM_PAGE)).rejects.toThrow("ERROR");
+ fd.close();
+ });
+ });
+
+ describe("os backend extras", function () {
+ const fileName = "test_os_extras.bin";
+
+ afterEach(async () => {
+ try { await fs.promises.unlink(fileName); } catch (e) { /* may not exist */ }
+ });
+
+ it("round-trips the numeric helpers", async () => {
+ const fd = await fastFile.createOverride(fileName);
+ await roundTripHelpers(fd);
+ await fd.close();
+ });
+
+ it("grows a sub-blksize pageSize up to the filesystem block size", async () => {
+ const fd = await fastFile.createOverride(fileName, 1 << 16, 256);
+ assert.strictEqual(fd.pageSize % 256, 0);
+ const stats = await fs.promises.stat(fileName);
+ assert(fd.pageSize >= stats.blksize);
+ await fd.close();
+ });
+
+ it("readString spans multiple pages", async () => {
+ const enc = new TextEncoder();
+ const fd = await fastFile.createOverride(fileName, 1 << 16, 1 << 12);
+ const long = "s".repeat(10000); // > 2 pages of 4096
+ await fd.write(enc.encode(long), 0);
+ await fd.write(new Uint8Array([0]), 10000);
+ assert.strictEqual(await fd.readString(0), long);
+ await fd.close();
+ });
+
+ it("read(0) is a no-op and a direct-size read past EOF returns zero-filled bytes", async () => {
+ const fd = await fastFile.createOverride(fileName, 1 << 22, 1 << 12);
+ await fd.write(makeData(1 << 12), 0);
+ const empty = await fd.read(0, 0);
+ assert.strictEqual(empty.byteLength, 0);
+
+ // >= directReadThreshold (1 MiB) with pos beyond EOF: clamps to
+ // zero bytes read, destination stays zero-filled
+ const past = await fd.read(1 << 20, 1 << 21);
+ assert(past.every((b) => b === 0));
+ await fd.close();
+ });
+
+ it("a large read overlapping dirty pages takes the cached path", async () => {
+ const fd = await fastFile.createOverride(fileName, 1 << 23, 1 << 12);
+ const small = makeData(4096);
+ await fd.write(small, 0); // small cached write: page 0 is dirty
+ const got = await fd.read(1 << 20, 0); // direct-size read overlaps it
+ assert.deepStrictEqual([...got.slice(0, 64)], [...small.slice(0, 64)]);
+ await fd.close();
+ });
+
+ it("a direct-size write over previously cached pages stays coherent", async () => {
+ const fd = await fastFile.createOverride(fileName, 1 << 22, 1 << 12);
+ await fd.write(makeData(1 << 12), 0);
+ await fd.read(16, 0); // populate the page cache
+ const big = new Uint8Array(1 << 20).fill(0x5A);
+ await fd.write(big, 0); // >= directWriteThreshold with cached overlap
+ const got = await fd.read(32, 0);
+ assert(got.every((b) => b === 0x5A));
+ await fd.close();
+ });
+
+ it("discard closes and unlinks the file", async () => {
+ const fd = await fastFile.createOverride(fileName);
+ await fd.write(makeData(8), 0);
+ await fd.discard();
+ await expect(fs.promises.stat(fileName)).rejects.toThrow();
+ });
+
+ it("writing after close fails fast", async () => {
+ const fd = await fastFile.createOverride(fileName);
+ await fd.write(makeData(8), 0);
+ await fd.close();
+ await expect(fd.write(makeData(8), 0)).rejects.toThrow("Writing a closing file");
+ await expect(fd.readString(0)).rejects.toThrow("Reading a closing file");
+ });
+ });
+
+ describe("blob backend (RangeFile)", function () {
+ function blobOf(data) {
+ return new Blob([data]);
+ }
+
+ it("round-trips numeric helpers and strings, and evicts old pages", async () => {
+ const enc = new TextEncoder();
+ const data = new Uint8Array(1 << 16);
+ data.set([4, 3, 2, 1], 0); // ULE32 0x01020304
+ data.set([0x0A, 0x0B, 0x0C, 0x0D], 4); // UBE32
+ data.set([0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0, 0, 0], 8); // ULE64 0x1FFFFFFFFF
+ data.set(enc.encode("blob-str"), 16);
+ data[24] = 0;
+
+ // pageSize 4 KiB, cacheSize == pageSize -> maxPagesLoaded 2:
+ // touching many pages exercises cache eviction
+ const fd = await fastFile.readExisting({ type: "blob", blob: blobOf(data), cacheSize: 1 << 12, pageSize: 1 << 12 });
+ assert.strictEqual(await fd.readULE32(0), 0x01020304);
+ assert.strictEqual(await fd.readUBE32(4), 0x0A0B0C0D);
+ assert.strictEqual(await fd.readULE64(8), 0x1FFFFFFFFF);
+ assert.strictEqual(await fd.readString(16), "blob-str");
+ for (let p = 0; p < 8; p++) {
+ await fd.read(4, p * (1 << 12));
+ }
+ assert(fd.pages.size <= fd.maxPagesLoaded);
+ await fd.close();
+ });
+
+ it("readString without a terminator ends at EOF; sequential reads advance pos", async () => {
+ const enc = new TextEncoder();
+ const fd = await fastFile.readExisting({ type: "blob", blob: blobOf(enc.encode("abc\0defgh")) });
+ assert.strictEqual(await fd.readString(), "abc");
+ assert.strictEqual(await fd.readString(), "defgh"); // runs to EOF
+ await fd.close();
+ });
+
+ it("rejects out-of-bounds reads and every write helper", async () => {
+ const fd = await fastFile.readExisting({ type: "blob", blob: blobOf(makeData(16)) });
+ await expect(fd.read(32, 0)).rejects.toThrow("Reading out of bounds");
+ await expect(fd.write(new Uint8Array(1), 0)).rejects.toThrow("read only");
+ await expect(fd.writeULE32(1, 0)).rejects.toThrow("read only");
+ await expect(fd.writeUBE32(1, 0)).rejects.toThrow("read only");
+ await expect(fd.writeULE64(1, 0)).rejects.toThrow("read only");
+ await fd.discard(); // close()s; second close via discard is a no-op
+ await expect(fd.readString(0)).rejects.toThrow("Reading a closing file");
+ });
+
+ it("surfaces short reads from a lying blob", async () => {
+ const fake = {
+ size: 100,
+ slice: function () {
+ return { arrayBuffer: function () { return Promise.resolve(new ArrayBuffer(1)); } };
+ }
+ };
+ const fd = await fastFile.readExisting({ type: "blob", blob: fake });
+ await expect(fd.read(50, 0)).rejects.toThrow("short blob read");
+ // the failed page load was evicted, not cached
+ assert.strictEqual(fd.pages.size, 0);
+ });
+ });
+
+ describe("http backend probe fallbacks", function () {
+ // Minimal configurable server: `mode` selects the probe behavior.
+ function startServer(data, mode) {
+ const server = http.createServer(function (req, res) {
+ const range = req.headers.range;
+ if (!range) { // plain GET (readFullyToMem)
+ res.writeHead(200, { "Content-Length": data.length });
+ res.end(Buffer.from(data));
+ return;
+ }
+ const m = /^bytes=(\d+)-(\d+)$/.exec(range);
+ const start = parseInt(m[1]);
+ const end = Math.min(parseInt(m[2]), data.length - 1);
+ const isProbe = start === 0 && parseInt(m[1]) === 0 && parseInt(m[2]) === 0;
+
+ if (mode === "probe-500") {
+ res.writeHead(500); res.end("boom"); return;
+ }
+ if (mode === "416-empty") {
+ res.writeHead(416, { "Content-Range": "bytes */0" }); res.end(); return;
+ }
+ if (mode === "416-other") {
+ res.writeHead(416, { "Content-Range": "bytes */" + data.length }); res.end(); return;
+ }
+ if (mode === "no-total") {
+ res.writeHead(206, { "Content-Range": "bytes 0-0/*", "Content-Length": 1 });
+ res.end(Buffer.from(data.slice(0, 1))); return;
+ }
+ if (mode === "fail-after-probe" && !isProbe) {
+ res.writeHead(500); res.end("boom"); return;
+ }
+ if (mode === "wrong-start" && !isProbe) {
+ const body = Buffer.from(data.slice(start + 1, end + 2));
+ res.writeHead(206, {
+ "Content-Range": "bytes " + (start + 1) + "-" + (end + 1) + "/" + data.length,
+ "Content-Length": body.length
+ });
+ res.end(body); return;
+ }
+ if (mode === "overlong" && !isProbe) {
+ const body = Buffer.concat([Buffer.from(data.slice(start, end + 1)), Buffer.alloc(10, 7)]);
+ res.writeHead(206, {
+ "Content-Range": "bytes " + start + "-" + end + "/" + data.length,
+ "Content-Length": body.length
+ });
+ res.end(body); return;
+ }
+ if (mode === "short" && !isProbe) {
+ const body = Buffer.from(data.slice(start, end)); // one byte short
+ res.writeHead(206, {
+ "Content-Range": "bytes " + start + "-" + end + "/" + data.length,
+ "Content-Length": body.length
+ });
+ res.end(body); return;
+ }
+ const body = Buffer.from(data.slice(start, end + 1));
+ res.writeHead(206, {
+ "Content-Range": "bytes " + start + "-" + end + "/" + data.length,
+ "Content-Length": body.length,
+ "ETag": "\"v1\""
+ });
+ res.end(body);
+ });
+ return new Promise(function (resolve) {
+ server.listen(0, "127.0.0.1", function () {
+ resolve({
+ url: "http://127.0.0.1:" + server.address().port + "/f.bin",
+ close: function () { return new Promise(function (r) { server.close(r); }); }
+ });
+ });
+ });
+ }
+
+ it("buffers fully when the total size is unknown (Content-Range */*)", async () => {
+ const data = makeData(4096);
+ const srv = await startServer(data, "no-total");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ assert.strictEqual(fd.totalSize, data.length);
+ assert.deepStrictEqual([...(await fd.read(8, 100))], [...data.slice(100, 108)]);
+ fd.close();
+ } finally { await srv.close(); }
+ });
+
+ it("throws on a failing probe", async () => {
+ const srv = await startServer(makeData(16), "probe-500");
+ try {
+ await expect(fastFile.readExisting(srv.url)).rejects.toThrow("HTTP 500");
+ } finally { await srv.close(); }
+ });
+
+ it("treats 416 with a zero total as an empty file", async () => {
+ const srv = await startServer(new Uint8Array(0), "416-empty");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ assert.strictEqual(fd.totalSize, 0);
+ fd.close();
+ } finally { await srv.close(); }
+ });
+
+ it("falls back to a full fetch on other 416 responses", async () => {
+ const data = makeData(64);
+ const srv = await startServer(data, "416-other");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ assert.strictEqual(fd.totalSize, data.length);
+ fd.close();
+ } finally { await srv.close(); }
+ });
+
+ it("rejects a range answered at the wrong offset", async () => {
+ const srv = await startServer(makeData(1 << 17), "wrong-start");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await expect(fd.read(1 << 16, 0)).rejects.toThrow("server returned range starting at");
+ fd.close();
+ } finally { await srv.close(); }
+ });
+
+ it("rejects a range response longer than requested", async () => {
+ const srv = await startServer(makeData(1 << 17), "overlong");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await expect(fd.read(1 << 16, 0)).rejects.toThrow("longer than requested");
+ fd.close();
+ } finally { await srv.close(); }
+ });
+
+ it("rejects a short range response", async () => {
+ const srv = await startServer(makeData(1 << 17), "short");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await expect(fd.read(1 << 16, 0)).rejects.toThrow("short range response");
+ fd.close();
+ } finally { await srv.close(); }
+ });
+
+ it("a failed page load is retried on the next read", async () => {
+ const srv = await startServer(makeData(1 << 14), "fail-after-probe");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await expect(fd.read(4, 0)).rejects.toThrow("HTTP 500");
+ // the rejected page was evicted so a retry issues a new request
+ await expect(fd.read(4, 0)).rejects.toThrow("HTTP 500");
+ fd.close();
+ } finally { await srv.close(); }
+ });
+ });
+});
diff --git a/test/bigmemfile.test.js b/test/bigmemfile.test.js
index 719bb4b..d94885e 100644
--- a/test/bigmemfile.test.js
+++ b/test/bigmemfile.test.js
@@ -1,16 +1,8 @@
import * as testUtils from "./testUtils.js";
import * as fastFile from "../src/fastfile.js";
-
-import assert from "assert";
-import * as chai from "chai";
-import chaiAsPromised from "chai-as-promised";
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
+import { expect } from "vitest";
describe("fastfile testing suite for bigMemFile", function () {
- this.timeout(100000);
-
let str1 = "0123456789";
let str2 = "Hi_there";
let str3 = "/!!--::**";
@@ -29,13 +21,13 @@ describe("fastfile testing suite for bigMemFile", function () {
await testUtils.writeStringToFile(fd, str3);
let str = await fd.readString((1 << 22) - 9);
- assert.strictEqual(str, str1);
+ expect(str).toBe(str1);
str = await fd.readString();
- assert.strictEqual(str, str2);
+ expect(str).toBe(str2);
str = await fd.readString();
- assert.strictEqual(str, str3);
+ expect(str).toBe(str3);
await fd.close();
});
@@ -47,8 +39,8 @@ describe("fastfile testing suite for bigMemFile", function () {
byteLength: 1
}]
};
- let fd = await fastFile.readExisting(file);
- expect(fd.readString(10)).to.be.rejectedWith("Reading out of bounds");
+ const fd = await fastFile.readExisting(file);
+ await expect(fd.readString(10)).rejects.toThrow("Reading out of bounds");
});
});
diff --git a/test/blobfile.test.js b/test/blobfile.test.js
new file mode 100644
index 0000000..50ec9fc
--- /dev/null
+++ b/test/blobfile.test.js
@@ -0,0 +1,46 @@
+import * as fastFile from "../src/fastfile.js";
+
+import assert from "assert";
+import { expect } from "vitest";
+
+
+function makeData(n) {
+ const data = new Uint8Array(n);
+ let x = 0x9E3779B9;
+ for (let i = 0; i < n; i++) {
+ x ^= x << 13; x >>>= 0;
+ x ^= x >> 17;
+ x ^= x << 5; x >>>= 0;
+ data[i] = x & 0xFF;
+ }
+ return data;
+}
+
+describe("fastfile testing suite for blobfile", function () {
+
+ it("should read positioned ranges from a Blob", async () => {
+ const data = makeData(1 << 18);
+ const fd = await fastFile.readExisting(new Blob([data]));
+ assert.strictEqual(fd.totalSize, data.length);
+
+ const head = await fd.read(4, 0);
+ assert.deepStrictEqual(Buffer.from(head), Buffer.from(data.slice(0, 4)));
+
+ const big = new Uint8Array(100000);
+ await fd.readToBuffer(big, 0, big.length, 30000);
+ assert.deepStrictEqual(Buffer.from(big), Buffer.from(data.slice(30000, 130000)));
+
+ const v = await fd.readULE64(1024);
+ const dv = new DataView(data.buffer);
+ assert.strictEqual(v, dv.getUint32(1028, true) * 0x100000000 + dv.getUint32(1024, true));
+
+ await fd.close();
+ });
+
+ it("should reject reads out of bounds and any write", async () => {
+ const fd = await fastFile.readExisting(new Blob([makeData(100)]));
+ await expect(fd.read(8, 96)).rejects.toThrow(/out of bounds/);
+ await expect(fd.write(new Uint8Array(4), 0)).rejects.toThrow(/read only/);
+ await fd.close();
+ });
+});
diff --git a/test/fastfile.browser.test.js b/test/fastfile.browser.test.js
new file mode 100644
index 0000000..e8d9446
--- /dev/null
+++ b/test/fastfile.browser.test.js
@@ -0,0 +1,120 @@
+import * as fastFile from "../src/fastfile.browser.js";
+import * as testUtils from "./testUtils.js";
+import { vi, expect } from "vitest";
+
+describe("fastfile browser — mem", function () {
+ const str1 = "0123456789";
+ const str2 = "Hi_there";
+ const str3 = "/!!--::**";
+
+ it("should read valid strings from mem file", async () => {
+ const fd = await fastFile.createOverride({ type: "mem" });
+
+ await testUtils.writeFakeStringToFile(fd, 10);
+ await testUtils.writeStringToFile(fd, str1);
+ await testUtils.writeStringToFile(fd, str2);
+ await testUtils.writeStringToFile(fd, str3);
+
+ let str = await fd.readString(10);
+ expect(str).toBe(str1);
+
+ str = await fd.readString();
+ expect(str).toBe(str2);
+
+ str = await fd.readString();
+ expect(str).toBe(str3);
+
+ await fd.close();
+ });
+
+ it("createNoOverride is an alias for createOverride in browser", async () => {
+ const fd = await fastFile.createNoOverride({ type: "mem" });
+ expect(fd).toBeTruthy();
+ await fd.close();
+ });
+
+ it("readExisting from Uint8Array", async () => {
+ const data = new Uint8Array([10, 20, 30]);
+ const fd = await fastFile.readExisting(data);
+ const result = await fd.read(3, 0);
+ expect([...result]).toEqual([10, 20, 30]);
+ await fd.close();
+ });
+
+ it("readExisting from a Blob streams through the blob backend", async () => {
+ const bytes = new Uint8Array(64 * 1024);
+ for (let i = 0; i < bytes.length; i++) bytes[i] = i & 0xff;
+ const fd = await fastFile.readExisting(new Blob([bytes]));
+ expect(fd.totalSize).toBe(bytes.length);
+ // small read (page-cached) and large read (direct slice) both match
+ const head = await fd.read(16, 0);
+ expect([...head]).toEqual([...bytes.subarray(0, 16)]);
+ const tail = await fd.read(32 * 1024, 32 * 1024);
+ expect([...tail]).toEqual([...bytes.subarray(32 * 1024)]);
+ await fd.close();
+ });
+
+ it("readExisting from URL fetches data", async () => {
+ const mockData = new Uint8Array([1, 2, 3]);
+ // A server that ignores Range and sends the whole body (the http
+ // backend probes with Range: bytes=0-0 and falls back to buffering).
+ vi.stubGlobal("fetch", () =>
+ Promise.resolve({
+ ok: true,
+ status: 200,
+ arrayBuffer: () => Promise.resolve(mockData.buffer.slice(0)),
+ })
+ );
+ try {
+ const fd = await fastFile.readExisting("https://example.com/test.bin");
+ const result = await fd.read(3, 0);
+ expect([...result]).toEqual([1, 2, 3]);
+ await fd.close();
+ } finally {
+ vi.unstubAllGlobals();
+ }
+ });
+
+ it("throws when using file type", () => {
+ expect(() => fastFile.createOverride({ type: "file", fileName: "test" }))
+ .toThrow("not supported in the browser");
+ });
+
+ it("readWriteExistingOrCreate is an alias for readWriteExisting", async () => {
+ const o = { type: "mem", data: new Uint8Array([5, 6, 7]) };
+ const fd = await fastFile.readWriteExistingOrCreate(o);
+ expect(fd).toBeTruthy();
+ await fd.close();
+ });
+});
+
+describe("fastfile browser — bigMem", function () {
+ const str1 = "0123456789";
+ const str2 = "Hi_there";
+ const str3 = "/!!--::**";
+
+ it("should read valid strings from bigMem file", async () => {
+ const fd = await fastFile.createOverride({ type: "bigMem" });
+
+ await testUtils.writeFakeStringToFile(fd, 10);
+ await testUtils.writeStringToFile(fd, str1);
+ await testUtils.writeStringToFile(fd, str2);
+ await testUtils.writeStringToFile(fd, str3);
+
+ let str = await fd.readString(10);
+ expect(str).toBe(str1);
+
+ str = await fd.readString();
+ expect(str).toBe(str2);
+
+ str = await fd.readString();
+ expect(str).toBe(str3);
+
+ await fd.close();
+ });
+
+ it("throws for file type on bigMem project", () => {
+ expect(() => fastFile.readWriteExisting({ type: "file" }))
+ .toThrow("not supported in the browser");
+ });
+});
diff --git a/test/httpfile.test.js b/test/httpfile.test.js
new file mode 100644
index 0000000..6ad2569
--- /dev/null
+++ b/test/httpfile.test.js
@@ -0,0 +1,459 @@
+import * as fastFile from "../src/fastfile.js";
+
+import http from "http";
+import assert from "assert";
+import { expect } from "vitest";
+
+
+// Deterministic pseudo-random content so failures are reproducible.
+function makeData(n) {
+ const data = new Uint8Array(n);
+ let x = 0x12345678;
+ for (let i = 0; i < n; i++) {
+ x ^= x << 13; x >>>= 0;
+ x ^= x >> 17;
+ x ^= x << 5; x >>>= 0;
+ data[i] = x & 0xFF;
+ }
+ return data;
+}
+
+// Minimal static server. opts:
+// ranges: false -> ignore Range headers, always 200 full body
+// etag -> served as ETag; If-Range mismatches answer 200 full
+// state.data / state.etag may be swapped mid-test to simulate a changed file.
+function startServer(state, opts) {
+ opts = opts || {};
+ const log = { requests: [], bytesServed: 0, maxResponse: 0 };
+ const server = http.createServer(function (req, res) {
+ const entry = { range: req.headers.range || null, ifRange: req.headers["if-range"] || null };
+ log.requests.push(entry);
+ const data = state.data;
+ const headers = {};
+ if (state.etag) headers["ETag"] = state.etag;
+
+ const m = (opts.ranges !== false && req.headers.range) ?
+ /^bytes=(\d+)-(\d+)$/.exec(req.headers.range) : null;
+ const ifRangeOk = !req.headers["if-range"] || req.headers["if-range"] === state.etag;
+
+ if (m && ifRangeOk) {
+ const start = parseInt(m[1]);
+ if (start >= data.length) {
+ headers["Content-Range"] = "bytes */" + data.length;
+ res.writeHead(416, headers);
+ res.end();
+ return;
+ }
+ const end = Math.min(parseInt(m[2]), data.length - 1);
+ const body = Buffer.from(data.slice(start, end + 1));
+ headers["Content-Range"] = "bytes " + start + "-" + end + "/" + data.length;
+ headers["Content-Length"] = body.length;
+ headers["Accept-Ranges"] = "bytes";
+ res.writeHead(206, headers);
+ log.bytesServed += body.length;
+ log.maxResponse = Math.max(log.maxResponse, body.length);
+ res.end(body);
+ } else {
+ const body = Buffer.from(data);
+ headers["Content-Length"] = body.length;
+ res.writeHead(200, headers);
+ log.bytesServed += body.length;
+ res.end(body);
+ }
+ });
+ return new Promise(function (resolve) {
+ server.listen(0, "127.0.0.1", function () {
+ resolve({
+ server: server,
+ log: log,
+ url: "http://127.0.0.1:" + server.address().port + "/data.bin",
+ close: function () {
+ return new Promise(function (res2) { server.close(res2); });
+ }
+ });
+ });
+ });
+}
+
+describe("fastfile testing suite for httpfile", function () {
+
+ describe("unstable connections (retry + stall timeout)", () => {
+ let saved;
+ beforeEach(async () => {
+ const { httpRetryConfig } = await import("../src/httpfile.js");
+ saved = { ...httpRetryConfig };
+ httpRetryConfig.backoffMs = 10;
+ httpRetryConfig.stallTimeoutMs = 250;
+ });
+ afterEach(async () => {
+ const { httpRetryConfig } = await import("../src/httpfile.js");
+ Object.assign(httpRetryConfig, saved);
+ });
+
+ // Minimal faulty range server: `plan` decides per zkey request.
+ function faultyServer(data, plan) {
+ let n = 0;
+ const server = http.createServer((req, res) => {
+ const m = /^bytes=(\d+)-(\d+)$/.exec(req.headers.range || "");
+ const start = m ? parseInt(m[1]) : 0;
+ const end = m ? Math.min(parseInt(m[2]), data.length - 1) : data.length - 1;
+ const isProbe = start === 0 && end === 0;
+ const action = isProbe ? "ok" : plan(++n);
+ if (action === "503") { res.writeHead(503); res.end(); return; }
+ res.writeHead(action === "404" ? 404 : 206, {
+ "Content-Range": `bytes ${start}-${end}/${data.length}`,
+ "Content-Length": end - start + 1,
+ "ETag": "\"u1\"", "Accept-Ranges": "bytes",
+ });
+ if (action === "404") { res.end(); return; }
+ const body = Buffer.from(data.slice(start, end + 1));
+ if (action === "drop") {
+ res.write(body.subarray(0, Math.floor(body.length / 2)));
+ setTimeout(() => res.destroy(), 10);
+ return;
+ }
+ if (action === "stall") {
+ res.write(body.subarray(0, 16)); // then silence, socket open
+ return;
+ }
+ res.end(body);
+ });
+ return new Promise((r) => server.listen(0, "127.0.0.1", () => r({
+ url: `http://127.0.0.1:${server.address().port}/f.bin`,
+ attempts: () => n,
+ close: () => new Promise((x) => { server.closeAllConnections(); server.close(x); }),
+ })));
+ }
+
+ it("recovers from a mid-body connection drop", async () => {
+ const data = makeData(1 << 18);
+ const srv = await faultyServer(data, (n) => (n === 1 ? "drop" : "ok"));
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ const got = await fd.read(200000, 1000);
+ assert.deepStrictEqual(Buffer.from(got), Buffer.from(data.slice(1000, 201000)));
+ await fd.close();
+ assert.strictEqual(srv.attempts(), 2);
+ } finally { await srv.close(); }
+ });
+
+ it("retries transient 503s but fails fast on 404", async () => {
+ const data = makeData(1 << 17);
+ const srv = await faultyServer(data, (n) => (n <= 2 ? "503" : "ok"));
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ const got = await fd.read(65536, 0);
+ assert.deepStrictEqual(Buffer.from(got), Buffer.from(data.slice(0, 65536)));
+ await fd.close();
+ assert.strictEqual(srv.attempts(), 3);
+ } finally { await srv.close(); }
+
+ const srv2 = await faultyServer(data, () => "404");
+ try {
+ const fd = await fastFile.readExisting(srv2.url);
+ await expect(fd.read(65536, 0)).rejects.toThrow("HTTP 404");
+ assert.strictEqual(srv2.attempts(), 1); // permanent: no retry
+ await fd.close();
+ } finally { await srv2.close(); }
+ });
+
+ it("aborts a stalled response and recovers on retry", async () => {
+ const data = makeData(1 << 18);
+ const srv = await faultyServer(data, (n) => (n === 1 ? "stall" : "ok"));
+ try {
+ const t0 = Date.now();
+ const fd = await fastFile.readExisting(srv.url);
+ const got = await fd.read(150000, 5000);
+ assert.deepStrictEqual(Buffer.from(got), Buffer.from(data.slice(5000, 155000)));
+ await fd.close();
+ assert.strictEqual(srv.attempts(), 2);
+ assert.ok(Date.now() - t0 < 5000, "stall was not bounded");
+ } finally { await srv.close(); }
+ });
+
+ it("gives up after exhausting retries", async () => {
+ const data = makeData(1 << 17);
+ const srv = await faultyServer(data, () => "503");
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await expect(fd.read(65536, 0)).rejects.toThrow("HTTP 503");
+ assert.strictEqual(srv.attempts(), 4); // 1 try + 3 retries
+ await fd.close();
+ } finally { await srv.close(); }
+ });
+ });
+
+ it("caps concurrent range fetches below the browser connection limit", async () => {
+ const data = makeData(1 << 20);
+ let inFlight = 0, maxInFlight = 0;
+ const fakeFetch = async (url, opts) => {
+ const m = /bytes=(\d+)-(\d+)/.exec((opts && opts.headers && opts.headers["Range"]) || "");
+ const from = m ? parseInt(m[1]) : 0;
+ const to = m ? Math.min(parseInt(m[2]), data.length - 1) : data.length - 1;
+ inFlight++; maxInFlight = Math.max(maxInFlight, inFlight);
+ await new Promise((r) => setTimeout(r, 20));
+ inFlight--;
+ return {
+ ok: true, status: 206,
+ headers: new Map([
+ ["content-range", `bytes ${from}-${to}/${data.length}`],
+ ["etag", "\"cap\""],
+ ]),
+ arrayBuffer: async () => data.slice(from, to + 1).buffer,
+ body: null,
+ };
+ };
+ fakeFetch.headersGet = true;
+ const realFetch = globalThis.fetch;
+ globalThis.fetch = (u, o) => fakeFetch(u, o).then((r) => ({ ...r, headers: { get: (k) => r.headers.get(k.toLowerCase()) } }));
+ try {
+ const fd = await fastFile.readExisting({ type: "http", url: "http://cap.example/f.bin" });
+ const reads = [];
+ for (let k = 0; k < 12; k++) reads.push(fd.read(70000, k * 80000)); // > pageSize: direct path
+ await Promise.all(reads);
+ await fd.close();
+ assert.ok(maxInFlight <= 4, "expected <= 4 concurrent range fetches, saw " + maxInFlight);
+ } finally {
+ globalThis.fetch = realFetch;
+ }
+ });
+
+ it("http cache option is a no-op where IndexedDB does not exist (Node)", async () => {
+ const data = makeData(1 << 18);
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ const fd = await fastFile.readExisting({
+ type: "http", url: srv.url, cache: true,
+ });
+ const got = await fd.read(64, 12345);
+ assert.deepStrictEqual(Buffer.from(got), Buffer.from(data.slice(12345, 12345 + 64)));
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should read ranges without ever downloading the full file", async () => {
+ const data = makeData(1 << 20); // 1 MiB
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ assert.strictEqual(fd.totalSize, data.length);
+
+ // header-style small reads
+ const head = await fd.read(4, 0);
+ assert.deepStrictEqual([...head], [...data.slice(0, 4)]);
+ const v = await fd.readULE32(4);
+ assert.strictEqual(v, new DataView(data.buffer).getUint32(4, true));
+
+ // large positioned read (direct path)
+ const big = new Uint8Array(300000);
+ await fd.readToBuffer(big, 0, big.length, 500000);
+ assert.deepStrictEqual(Buffer.from(big), Buffer.from(data.slice(500000, 800000)));
+
+ // scattered small reads (cached path), spanning a page boundary
+ const ps = fd.pageSize;
+ const cross = await fd.read(16, ps - 8);
+ assert.deepStrictEqual(Buffer.from(cross), Buffer.from(data.slice(ps - 8, ps + 8)));
+
+ await fd.close();
+
+ // every request carried a Range header (no full-file GET) ...
+ for (const r of srv.log.requests) assert.ok(r.range, "expected only range requests");
+ // ... and far less than the file was transferred
+ assert.ok(srv.log.bytesServed < data.length / 2,
+ "served " + srv.log.bytesServed + " of " + data.length);
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should serve repeated small reads on one page from cache (single request)", async () => {
+ const data = makeData(1 << 16);
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ const before = srv.log.requests.length;
+ await fd.read(4, 100);
+ await fd.read(4, 200);
+ await fd.readULE64(300);
+ assert.strictEqual(srv.log.requests.length, before + 1);
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should read sequentially without explicit positions", async () => {
+ const data = makeData(4096);
+ const srv = await startServer({ data: data });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ const a = await fd.read(10);
+ const b = await fd.read(10);
+ assert.deepStrictEqual(Buffer.concat([Buffer.from(a), Buffer.from(b)]), Buffer.from(data.slice(0, 20)));
+ assert.strictEqual(fd.pos, 20);
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should fall back to full buffering when the server ignores Range", async () => {
+ const data = makeData(100000);
+ const srv = await startServer({ data: data }, { ranges: false });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ assert.strictEqual(fd.totalSize, data.length);
+ const all = await fd.read(data.length, 0);
+ assert.deepStrictEqual(Buffer.from(all), Buffer.from(data));
+ await fd.close();
+ // the probe response body was reused: exactly one request
+ assert.strictEqual(srv.log.requests.length, 1);
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should fail a read when the remote file changes mid-session (If-Range)", async () => {
+ const state = { data: makeData(1 << 20), etag: "\"v1\"" };
+ const srv = await startServer(state);
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ const buff = new Uint8Array(1 << 16);
+ await fd.readToBuffer(buff, 0, buff.length, 0); // works on v1
+
+ state.data = makeData(1 << 20).map(function (b) { return b ^ 0xFF; });
+ state.etag = "\"v2\"";
+
+ // direct (uncached) read must reject, not silently mix versions
+ await expect(fd.readToBuffer(new Uint8Array(1 << 16), 0, 1 << 16, 1 << 17))
+ .rejects.toThrow(/file changed/);
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should reject reads out of bounds and any write", async () => {
+ const data = makeData(1000);
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await expect(fd.read(16, 992)).rejects.toThrow(/out of bounds/);
+ await expect(fd.write(new Uint8Array(4), 0)).rejects.toThrow(/read only/);
+ await expect(fd.writeULE32(1, 0)).rejects.toThrow(/read only/);
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("should cap disk-tuned page-size hints (small read must not fetch the file)", async () => {
+ const data = makeData(1 << 19); // 512 KiB, well under an 8 MiB "page"
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ // snarkjs-style hints: 32 MiB cache, 8 MiB pages (meant for disk)
+ const fd = await fastFile.readExisting(srv.url, 1 << 25, 1 << 23);
+ await fd.read(4, 0);
+ await fd.readULE64(300000);
+ assert.ok(srv.log.maxResponse <= 1 << 16,
+ "largest response was " + srv.log.maxResponse + " bytes; page hint not capped");
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("close() is idempotent on the http backend", async () => {
+ const data = makeData(1 << 12);
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ await fd.read(4, 0);
+ await fd.close();
+ await fd.close(); // second close: no-op, no throw
+ } finally {
+ await srv.close();
+ }
+ });
+
+ it("degrades to full buffering when the origin stops honoring Range (matching validator)", async () => {
+ // Browser scenario: the probe is answered 206 by an HTTP cache, but
+ // the origin itself ignores Range and answers 200 with the same
+ // strong ETag. Reads must succeed via buffered mode, not throw
+ // "file changed".
+ const data = makeData(1 << 18);
+ let first = true;
+ const server = http.createServer((req, res) => {
+ if (first && req.headers.range === "bytes=0-0") {
+ first = false;
+ res.writeHead(206, {
+ "Content-Range": "bytes 0-0/" + data.length,
+ "Content-Length": 1,
+ "ETag": "\"stable\"",
+ });
+ return res.end(Buffer.from(data.slice(0, 1)));
+ }
+ res.writeHead(200, { "Content-Length": data.length, "ETag": "\"stable\"" });
+ res.end(Buffer.from(data));
+ });
+ await new Promise((r) => server.listen(0, "127.0.0.1", r));
+ const url = "http://127.0.0.1:" + server.address().port + "/data.bin";
+ try {
+ const fd = await fastFile.readExisting(url);
+ assert.strictEqual(fd.totalSize, data.length);
+ const head = await fd.read(8, 0);
+ assert.deepStrictEqual([...head], [...data.slice(0, 8)]);
+ const mid = await fd.read(1 << 12, 1 << 17);
+ assert.deepStrictEqual([...mid], [...data.slice(1 << 17, (1 << 17) + (1 << 12))]);
+ await fd.close();
+ } finally {
+ await new Promise((r) => server.close(r));
+ }
+ });
+
+ it("still fails hard when a mid-session 200 carries a different validator", async () => {
+ const data = makeData(1 << 16);
+ let first = true;
+ const server = http.createServer((req, res) => {
+ if (first && req.headers.range === "bytes=0-0") {
+ first = false;
+ res.writeHead(206, {
+ "Content-Range": "bytes 0-0/" + data.length,
+ "Content-Length": 1,
+ "ETag": "\"v1\"",
+ });
+ return res.end(Buffer.from(data.slice(0, 1)));
+ }
+ res.writeHead(200, { "Content-Length": data.length, "ETag": "\"v2\"" });
+ res.end(Buffer.from(data));
+ });
+ await new Promise((r) => server.listen(0, "127.0.0.1", r));
+ const url = "http://127.0.0.1:" + server.address().port + "/data.bin";
+ try {
+ const fd = await fastFile.readExisting(url);
+ await expect(fd.read(64, 0)).rejects.toThrow(/file changed/);
+ await fd.close();
+ } finally {
+ await new Promise((r) => server.close(r));
+ }
+ });
+
+ it("should read strings through the page cache", async () => {
+ const data = makeData(9000);
+ const msg = "hello_snarkjs";
+ for (let i = 0; i < msg.length; i++) data[8000 + i] = msg.charCodeAt(i);
+ data[8000 + msg.length] = 0;
+ const srv = await startServer({ data: data, etag: "\"v1\"" });
+ try {
+ const fd = await fastFile.readExisting(srv.url);
+ const str = await fd.readString(8000);
+ assert.strictEqual(str, msg);
+ assert.strictEqual(fd.pos, 8000 + msg.length + 1);
+ await fd.close();
+ } finally {
+ await srv.close();
+ }
+ });
+});
diff --git a/test/idbcache.browser.test.js b/test/idbcache.browser.test.js
new file mode 100644
index 0000000..a502a6f
--- /dev/null
+++ b/test/idbcache.browser.test.js
@@ -0,0 +1,278 @@
+import * as fastFile from "../src/fastfile.browser.js";
+import { expect, vi } from "vitest";
+
+// In-Chromium tests for the IndexedDB-backed persistent block cache
+// (cache option of the http backend). fetch is stubbed with a
+// deterministic Range-honoring server that counts requests, so warm starts
+// are provable as "zero network requests".
+
+const FILE_SIZE = 5 * 1024 * 1024 + 123; // deliberately not block-aligned
+const BLOCK = 1 << 20; // 1 MiB test blocks
+
+function makeContent(seed) {
+ const data = new Uint8Array(FILE_SIZE);
+ for (let i = 0; i < data.length; i++) data[i] = (i * 31 + seed) & 0xff;
+ return data;
+}
+
+// A minimal Range-capable origin: 206 with Content-Range, strong ETag.
+function serveRanges(content, etag, counter) {
+ return (url, opts) => {
+ counter.count++;
+ const range = opts && opts.headers && opts.headers["Range"];
+ const m = /bytes=(\d+)-(\d+)/.exec(range || "");
+ const from = m ? parseInt(m[1]) : 0;
+ const to = m ? Math.min(parseInt(m[2]), content.length - 1) : content.length - 1;
+ counter.bytes += to - from + 1;
+ const body = content.slice(from, to + 1);
+ return Promise.resolve({
+ ok: true,
+ status: 206,
+ headers: new Headers({
+ "content-range": `bytes ${from}-${to}/${content.length}`,
+ "etag": etag,
+ }),
+ arrayBuffer: () => Promise.resolve(body.buffer.slice(0)),
+ body: null, // exercise the non-streaming fallback (jsdom-style)
+ });
+ };
+}
+
+async function openCached(url, cacheOpts) {
+ return fastFile.readExisting({
+ type: "http",
+ url,
+ cache: cacheOpts || { blockSize: BLOCK, dbName: "fastfile-test-cache" },
+ });
+}
+
+function clearDb(name) {
+ return new Promise((resolve) => {
+ const req = indexedDB.deleteDatabase(name);
+ req.onsuccess = req.onerror = req.onblocked = () => resolve();
+ });
+}
+
+describe("IndexedDB persistent block cache", function () {
+ const URL1 = "https://cache.example/circuit.zkey";
+
+ beforeEach(async () => {
+ // fresh DB per test -- but note the module keeps its connection
+ // per dbName, so tests use distinct dbNames where isolation matters
+ await clearDb("fastfile-test-cache");
+ });
+
+ afterEach(() => {
+ vi.unstubAllGlobals();
+ });
+
+ it("cold reads are correct across block boundaries and warm reads hit no network", async () => {
+ const content = makeContent(7);
+ const counter = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(content, "\"v1\"", counter));
+
+ const dbName = "fastfile-test-warm";
+ await clearDb(dbName);
+ const fd = await openCached(URL1, { blockSize: BLOCK, dbName });
+
+ // unaligned read spanning interior + boundary blocks
+ const big = await fd.read(3 * BLOCK, BLOCK + 17);
+ expect([...big.slice(0, 8)]).toEqual([...content.subarray(BLOCK + 17, BLOCK + 25)]);
+ expect([...big.slice(-8)]).toEqual([...content.subarray(4 * BLOCK + 9, 4 * BLOCK + 17)]);
+ // small header-style read
+ const head = await fd.read(16, 4);
+ expect([...head]).toEqual([...content.subarray(4, 20)]);
+ // tail read hitting the short last block
+ const tail = await fd.read(100, FILE_SIZE - 100);
+ expect([...tail]).toEqual([...content.subarray(FILE_SIZE - 100)]);
+ await fd.close();
+ const coldFetches = counter.count;
+ expect(coldFetches).toBeGreaterThan(0);
+
+ // warm start: new handle, same URL -- all reads served from IDB
+ const fd2 = await openCached(URL1, { blockSize: BLOCK, dbName });
+ const probeFetches = counter.count - coldFetches; // open() probe only
+ const big2 = await fd2.read(3 * BLOCK, BLOCK + 17);
+ expect([...big2.slice(0, 32)]).toEqual([...big.slice(0, 32)]);
+ const tail2 = await fd2.read(100, FILE_SIZE - 100);
+ expect([...tail2]).toEqual([...tail]);
+ await fd2.close();
+ expect(counter.count - coldFetches - probeFetches).toBe(0);
+ expect(probeFetches).toBe(1);
+ });
+
+ it("a changed validator invalidates the cached blocks", async () => {
+ const dbName = "fastfile-test-inval";
+ await clearDb(dbName);
+
+ const v1 = makeContent(1);
+ const c1 = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(v1, "\"v1\"", c1));
+ const fd1 = await openCached(URL1, { blockSize: BLOCK, dbName });
+ await fd1.read(64, 0);
+ await fd1.close();
+
+ // same URL, new content + new ETag
+ const v2 = makeContent(2);
+ const c2 = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(v2, "\"v2\"", c2));
+ const fd2 = await openCached(URL1, { blockSize: BLOCK, dbName });
+ const got = await fd2.read(64, 0);
+ await fd2.close();
+ expect([...got]).toEqual([...v2.subarray(0, 64)]);
+ expect(c2.count).toBeGreaterThan(1); // probe + at least one real refetch
+ });
+
+ it("LRU eviction drops the least recently opened file, never the current one", async () => {
+ const dbName = "fastfile-test-evict";
+ await clearDb(dbName);
+ const opts = { blockSize: BLOCK, dbName, maxBytes: 4 * BLOCK };
+
+ const contentA = makeContent(10);
+ const cA = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(contentA, "\"a1\"", cA));
+ const fa = await fastFile.readExisting({ type: "http", url: "https://cache.example/a.zkey", cache: opts });
+ await fa.read(3 * BLOCK, 0); // caches 3 MiB for A
+ await fa.close();
+
+ const contentB = makeContent(20);
+ const cB = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(contentB, "\"b1\"", cB));
+ const fb = await fastFile.readExisting({ type: "http", url: "https://cache.example/b.zkey", cache: opts });
+ await fb.read(3 * BLOCK, 0); // A(3) + B(3) > maxBytes at next open
+ await fb.close();
+
+ // reopening B evicts A (older lastUsed) and keeps B warm
+ const cB2 = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(contentB, "\"b1\"", cB2));
+ const fb2 = await fastFile.readExisting({ type: "http", url: "https://cache.example/b.zkey", cache: opts });
+ await fb2.read(3 * BLOCK, 0);
+ await fb2.close();
+ expect(cB2.count).toBe(1); // probe only: B stayed cached
+
+ // A must refetch its data
+ const cA2 = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(contentA, "\"a1\"", cA2));
+ const fa2 = await fastFile.readExisting({ type: "http", url: "https://cache.example/a.zkey", cache: opts });
+ const back = await fa2.read(64, 0);
+ await fa2.close();
+ expect([...back]).toEqual([...contentA.subarray(0, 64)]);
+ expect(cA2.count).toBeGreaterThan(1);
+ });
+
+ it("concurrent cold reads of one block fetch it once (in-flight dedupe)", async () => {
+ const dbName = "fastfile-test-dedupe";
+ await clearDb(dbName);
+ const content = makeContent(9);
+ const counter = { count: 0, bytes: 0 };
+ vi.stubGlobal("fetch", serveRanges(content, "\"d1\"", counter));
+
+ const fd = await openCached("https://cache.example/dedupe.zkey", { blockSize: BLOCK, dbName });
+ const afterOpen = counter.count; // the probe
+ // 8 concurrent direct reads inside block 0 (each is a boundary-case
+ // miss); without dedupe each fetched the whole block independently
+ const reads = [];
+ for (let k = 0; k < 8; k++) reads.push(fd.read(128 * 1024, k * 64 * 1024));
+ const got = await Promise.all(reads);
+ for (let k = 0; k < 8; k++) {
+ expect([...got[k].slice(0, 8)]).toEqual([...content.subarray(k * 64 * 1024, k * 64 * 1024 + 8)]);
+ }
+ await fd.close();
+ // block 0 once, plus at most one more block touched by the last read
+ expect(counter.count - afterOpen).toBeLessThanOrEqual(2);
+ });
+
+ it("full-download servers: body persists cold, 304 probe serves warm from cache", async () => {
+ const dbName = "fastfile-test-fulldl";
+ await clearDb(dbName);
+ const content = makeContent(11);
+ const etag = "\"full-v1\"";
+ const counter = { count: 0, bytes: 0 };
+ // Range-less origin honoring conditional requests: If-None-Match
+ // match -> bodyless 304; otherwise 200 with the whole body.
+ const fullServer = (url, opts) => {
+ counter.count++;
+ const inm = opts && opts.headers && opts.headers["If-None-Match"];
+ if (inm === etag) {
+ return Promise.resolve({ ok: false, status: 304, headers: new Headers({ etag }),
+ arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), body: null });
+ }
+ counter.bytes += content.length;
+ return Promise.resolve({ ok: true, status: 200, headers: new Headers({ etag }),
+ arrayBuffer: () => Promise.resolve(content.buffer.slice(0)), body: null });
+ };
+ vi.stubGlobal("fetch", fullServer);
+
+ const url = "https://cache.example/fulldl.zkey";
+ // cold: 200 with the whole body; body gets persisted
+ const fd = await openCached(url, { blockSize: BLOCK, dbName });
+ expect(fd.totalSize).toBe(content.length);
+ const a = await fd.read(64, 12345);
+ expect([...a]).toEqual([...content.subarray(12345, 12345 + 64)]);
+ await fd.close();
+ expect(counter.count).toBe(1);
+ expect(counter.bytes).toBe(content.length);
+
+ // warm: conditional probe -> 304, no body; reads served from IDB
+ const fd2 = await openCached(url, { blockSize: BLOCK, dbName });
+ expect(fd2.totalSize).toBe(content.length);
+ const b = await fd2.read(3 * BLOCK, BLOCK + 17);
+ expect([...b.slice(0, 8)]).toEqual([...content.subarray(BLOCK + 17, BLOCK + 25)]);
+ const tail = await fd2.read(100, FILE_SIZE - 100);
+ expect([...tail]).toEqual([...content.subarray(FILE_SIZE - 100)]);
+ await fd2.close();
+ expect(counter.count).toBe(2); // just the 304 probe
+ expect(counter.bytes).toBe(content.length); // no second body
+
+ // changed file: validator mismatch -> fresh 200, new bytes served
+ const v2 = makeContent(12);
+ const c2 = { count: 0, bytes: 0 };
+ const etag2 = "\"full-v2\"";
+ vi.stubGlobal("fetch", (u, opts) => {
+ c2.count++;
+ const inm = opts && opts.headers && opts.headers["If-None-Match"];
+ if (inm === etag2) {
+ return Promise.resolve({ ok: false, status: 304, headers: new Headers({ etag: etag2 }),
+ arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)), body: null });
+ }
+ c2.bytes += v2.length;
+ return Promise.resolve({ ok: true, status: 200, headers: new Headers({ etag: etag2 }),
+ arrayBuffer: () => Promise.resolve(v2.buffer.slice(0)), body: null });
+ });
+ const fd3 = await openCached(url, { blockSize: BLOCK, dbName });
+ const g = await fd3.read(64, 0);
+ expect([...g]).toEqual([...v2.subarray(0, 64)]);
+ await fd3.close();
+ expect(c2.bytes).toBe(v2.length); // one fresh body, re-persisted
+
+ // and the new version is warm on the next open
+ const fd4 = await openCached(url, { blockSize: BLOCK, dbName });
+ const h = await fd4.read(64, 0);
+ expect([...h]).toEqual([...v2.subarray(0, 64)]);
+ await fd4.close();
+ expect(c2.bytes).toBe(v2.length); // still only the one body
+ });
+
+ it("without a strong validator the reader works but nothing persists", async () => {
+ const dbName = "fastfile-test-noval";
+ await clearDb(dbName);
+ const content = makeContent(3);
+ const counter = { count: 0, bytes: 0 };
+ const server = serveRanges(content, "", counter);
+ vi.stubGlobal("fetch", (url, opts) => server(url, opts).then((r) => {
+ r.headers = new Headers({ "content-range": r.headers.get("content-range") });
+ return r;
+ }));
+
+ const fd = await openCached("https://cache.example/nova.zkey", { blockSize: BLOCK, dbName });
+ const got = await fd.read(64, 0);
+ expect([...got]).toEqual([...content.subarray(0, 64)]);
+ await fd.close();
+ const cold = counter.count;
+
+ const fd2 = await openCached("https://cache.example/nova.zkey", { blockSize: BLOCK, dbName });
+ await fd2.read(64, 0);
+ await fd2.close();
+ expect(counter.count).toBeGreaterThan(cold + 1); // re-fetched: no cache without validator
+ });
+});
diff --git a/test/memfile.test.js b/test/memfile.test.js
index 89c780a..67985db 100644
--- a/test/memfile.test.js
+++ b/test/memfile.test.js
@@ -1,16 +1,8 @@
import * as testUtils from "./testUtils.js";
import * as fastFile from "../src/fastfile.js";
-
-import assert from "assert";
-import * as chai from "chai";
-import chaiAsPromised from "chai-as-promised";
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
+import { expect } from "vitest";
describe("fastfile testing suite for memfile", function () {
- this.timeout(100000);
-
let str1 = "0123456789";
let str2 = "Hi_there";
let str3 = "/!!--::**";
@@ -29,13 +21,13 @@ describe("fastfile testing suite for memfile", function () {
await testUtils.writeStringToFile(fd, str3);
let str = await fd.readString(10);
- assert.strictEqual(str, str1);
+ expect(str).toBe(str1);
str = await fd.readString();
- assert.strictEqual(str, str2);
+ expect(str).toBe(str2);
str = await fd.readString();
- assert.strictEqual(str, str3);
+ expect(str).toBe(str3);
await fd.close();
});
@@ -47,8 +39,8 @@ describe("fastfile testing suite for memfile", function () {
byteLength: 1
}
};
- let fd = await fastFile.readExisting(file);
- expect(fd.readString(10)).to.be.rejectedWith("Reading out of bounds");
+ const fd = await fastFile.readExisting(file);
+ await expect(fd.readString(10)).rejects.toThrow("Reading out of bounds");
});
});
diff --git a/test/osfile.test.js b/test/osfile.test.js
index 855d644..603152d 100644
--- a/test/osfile.test.js
+++ b/test/osfile.test.js
@@ -1,19 +1,11 @@
import fs from "fs";
import * as testUtils from "./testUtils.js";
import * as fastFile from "../src/fastfile.js";
-
-import assert from "assert";
-import * as chai from "chai";
-import chaiAsPromised from "chai-as-promised";
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
+import { BigBuffer } from "ffjavascript";
+import { expect, assert } from "vitest";
describe("fastfile testing suite for osfile", function () {
let fileName = "test_osfile.bin";
-
- this.timeout(100000);
-
let str1 = "0123456789";
let str2 = "Hi_there";
let str3 = "/!!--::**";
@@ -28,29 +20,177 @@ describe("fastfile testing suite for osfile", function () {
await testUtils.writeStringToFile(fd, str3);
let str = await fd.readString(fd.pageSize - 11);
- assert.strictEqual(str, str1);
+ expect(str).toBe(str1);
str = await fd.readString();
- assert.strictEqual(str, str2);
+ expect(str).toBe(str2);
str = await fd.readString();
- assert.strictEqual(str, str3);
+ expect(str).toBe(str3);
await fd.close();
- assert(fs.existsSync(fileName));
-
await fs.promises.unlink(fileName);
});
it("should throw error when try to read a closed file", async () => {
+ const fd = await fastFile.createOverride(fileName);
+ await fd.close();
+ await expect(fd.readString(0)).rejects.toThrow("Reading a closing file");
+ await fs.promises.unlink(fileName);
+ });
+
+ // Regression: the direct-io fast paths hand the buffer to fd.read/fd.write,
+ // which require a real TypedArray. A BigBuffer (paged, not an ArrayBufferView)
+ // must fall back to the cached path. A direct read into a BigBuffer used to
+ // silently leave it unfilled -> corrupted ptau/zkey sections. The read must be
+ // >= directReadThreshold (1MB) so it would take the direct path if not gated.
+ it("should read a large section into a BigBuffer (direct-io must not bypass it)", async () => {
+ const N = 1 << 21; // 2 MB > directReadThreshold
+ const ref = new Uint8Array(N);
+ for (let i = 0; i < N; i++) ref[i] = (i * 131 + 7) & 0xff;
+
let fd = await fastFile.createOverride(fileName);
+ await fd.write(ref, 0);
await fd.close();
- expect(fd.readString(0)).to.be.rejectedWith("Reading a closing file");
+
+ fd = await fastFile.readExisting(fileName);
+ expect(ArrayBuffer.isView(new BigBuffer(8))).toBe(false);
+ const bb = new BigBuffer(N);
+ await fd.readToBuffer(bb, 0, N, 0);
+ await fd.close();
+
+ expect(Buffer.from(bb.slice(0, N)).equals(Buffer.from(ref))).toBe(true);
await fs.promises.unlink(fileName);
});
-});
+ it("should write a large section from a BigBuffer (direct-io must not bypass it)", async () => {
+ const N = 1 << 21; // 2 MB > directWriteThreshold
+ const ref = new Uint8Array(N);
+ for (let i = 0; i < N; i++) ref[i] = (i * 197 + 13) & 0xff;
+ const bb = new BigBuffer(N);
+ bb.set(ref, 0);
+ let fd = await fastFile.createOverride(fileName);
+ await fd.write(bb, 0);
+ await fd.close();
+ const onDisk = fs.readFileSync(fileName);
+ expect(onDisk.length).toBe(N);
+ expect(onDisk.equals(Buffer.from(ref))).toBe(true);
+ await fs.promises.unlink(fileName);
+ });
+ // Regression: readToBuffer's cached-page path (reads below directReadThreshold,
+ // i.e. the common case for most zkey/ptau/wtns sections) computed the
+ // destination-buffer offset as `offset + len - r`, where `r` had already been
+ // clamped to the EOF-truncated byte count. That put the on-disk bytes at a
+ // nonzero offset in the output instead of at the start, and left the START of
+ // the buffer as zeros instead of the tail -- valid bytes silently shifted to
+ // the wrong position rather than the read cleanly failing or zero-padding
+ // only the truncated tail. This simulates a corrupted/incomplete file (a
+ // section header claims more bytes than the file actually has).
+ it("readToBuffer past EOF on a truncated file places real bytes at the start, not shifted (below directReadThreshold)", async () => {
+ const declaredLen = 2000; // < directReadThreshold (1MB): exercises the cached-page path
+ const actualLen = 1000; // how many bytes actually exist past `pos`
+ const pos = 24; // simulate a section starting after a small header
+
+ let fd = await fastFile.createOverride(fileName);
+ await fd.write(new Uint8Array(pos + actualLen).fill(0xAB), 0);
+ await fd.close();
+
+ assert.strictEqual(fs.statSync(fileName).size, pos + actualLen);
+
+ fd = await fastFile.readExisting(fileName);
+ const buff = await fd.read(declaredLen, pos);
+ await fd.close();
+
+ assert.strictEqual(buff.length, declaredLen);
+ // The real on-disk bytes must land at the START of the buffer...
+ for (let i = 0; i < actualLen; i++) {
+ assert.strictEqual(buff[i], 0xAB, `expected real data at index ${i}`);
+ }
+ // ...and only the truncated TAIL (bytes that don't exist on disk) is zero.
+ for (let i = actualLen; i < declaredLen; i++) {
+ assert.strictEqual(buff[i], 0, `expected zero padding at index ${i}`);
+ }
+ await fs.promises.unlink(fileName);
+ });
+
+ // Regression: when a page read failed, only the FIRST waiter was rejected;
+ // co-readers queued on page.loading hung forever, and the page stayed
+ // cached with a dead loading list so every future reader of it hung too.
+ it("a failed page read rejects all waiters and the page recovers", async () => {
+ fs.writeFileSync(fileName, new Uint8Array(1 << 16).fill(0xab));
+ const fd = await fastFile.readExisting(fileName, 1 << 20, 1 << 12);
+
+ const realRead = fd.fd.read.bind(fd.fd);
+ let failures = 1;
+ fd.fd.read = (...args) => {
+ if (failures > 0) { failures--; return Promise.reject(new Error("simulated EIO")); }
+ return realRead(...args);
+ };
+
+ // Two concurrent readers of the same page: both must settle (reject
+ // or, for the one that arrives after recovery, resolve) -- never hang.
+ const r1 = await fd.read(64, 0).then(() => "resolved", () => "rejected");
+ const r2 = await fd.read(64, 128).then(() => "resolved", () => "rejected");
+ assert(r1 === "rejected" || r2 === "rejected", "at least one reader sees the EIO");
+
+ // A later reader of the same page must succeed (page not poisoned).
+ const b = await fd.read(64, 0);
+ assert.strictEqual(b[0], 0xab);
+ await fd.close();
+ await fs.promises.unlink(fileName);
+ });
+
+ // Regression: a failed background page flush was only visible at close();
+ // page.writing also stayed true, pinning the page. Subsequent writes/reads
+ // must now fail fast and close() must reject.
+ it("close() is idempotent: repeated and concurrent closes resolve", async () => {
+ const fd = await fastFile.createOverride(fileName);
+ await testUtils.writeStringToFile(fd, str1);
+
+ // concurrent double close: both settle without throwing
+ await Promise.all([fd.close(), fd.close()]);
+ // close after close: still a no-op
+ await fd.close();
+
+ // I/O after close keeps failing fast
+ await expect(fd.read(4, 0)).rejects.toThrow("Reading a closing file");
+
+ await fs.promises.unlink(fileName);
+ });
+
+ it("a failing close() rejects every caller with the same error", async () => {
+ const fd = await fastFile.createOverride(fileName, 1 << 20, 1 << 12);
+
+ const realWrite = fd.fd.write.bind(fd.fd);
+ fd.fd.write = () => Promise.reject(new Error("simulated ENOSPC"));
+ await fd.write(new Uint8Array(64).fill(1), 0); // dirty page; flush will fail
+
+ await expect(fd.close()).rejects.toThrow("simulated ENOSPC");
+ // the repeated close reports the same failure instead of throwing
+ // "Closing the file twice"
+ await expect(fd.close()).rejects.toThrow("simulated ENOSPC");
+
+ fd.fd.write = realWrite;
+ await fs.promises.unlink(fileName);
+ });
+
+ it("a failed background write surfaces on the next write and on close()", async () => {
+ const fd = await fastFile.createOverride(fileName, 1 << 20, 1 << 12);
+
+ const realWrite = fd.fd.write.bind(fd.fd);
+ fd.fd.write = () => Promise.reject(new Error("simulated ENOSPC"));
+
+ await fd.write(new Uint8Array(64).fill(1), 0); // dirty page; background flush fails
+ await new Promise((resolve) => setTimeout(resolve, 50));
+
+ await expect(fd.write(new Uint8Array(64).fill(2), 4096)).rejects.toThrow("simulated ENOSPC");
+ await expect(fd.close()).rejects.toThrow("simulated ENOSPC");
+
+ fd.fd.write = realWrite; // let the underlying fd close cleanly
+ await fs.promises.unlink(fileName);
+ });
+});
diff --git a/test/size_fallbacks.test.js b/test/size_fallbacks.test.js
new file mode 100644
index 0000000..a758377
--- /dev/null
+++ b/test/size_fallbacks.test.js
@@ -0,0 +1,65 @@
+import fs from "fs";
+import * as fastFile from "../src/fastfile.js";
+import { afterAll, expect } from "vitest";
+
+// The b/c (cacheSize/pageSize) arguments of the entry points historically
+// applied only to string/Blob sources; a descriptor object without explicit
+// sizes silently got the small built-in defaults. They now act as fallbacks
+// for object sources too, filling exactly the fields the caller left
+// undefined -- so e.g. snarkjs passing {type: "file"} gets the same tuned
+// cache as when it passes a plain path string.
+describe("cacheSize/pageSize fallbacks for descriptor objects", function () {
+ const fileName = "test_size_fallbacks.bin";
+
+ afterAll(() => {
+ if (fs.existsSync(fileName)) fs.unlinkSync(fileName);
+ });
+
+ it("object source picks up the fallback sizes it does not set", async () => {
+ const fdString = await fastFile.createOverride(fileName, 1 << 22, 1 << 16);
+ await fdString.write(new Uint8Array(64), 0);
+ await fdString.close();
+
+ const fdObject = await fastFile.readExisting({ type: "file", fileName }, 1 << 22, 1 << 16);
+ const fdPlain = await fastFile.readExisting(fileName, 1 << 22, 1 << 16);
+ // identical tuning to the string source
+ expect(fdObject.pageSize).toBe(fdPlain.pageSize);
+ expect(fdObject.maxPagesLoaded).toBe(fdPlain.maxPagesLoaded);
+ await fdObject.close();
+ await fdPlain.close();
+ });
+
+ it("explicit object fields win over the fallbacks", async () => {
+ const fd = await fastFile.readExisting(
+ { type: "file", fileName, cacheSize: 1 << 20, pageSize: 1 << 13 }, 1 << 25, 1 << 16);
+ const fdRef = await fastFile.readExisting(
+ { type: "file", fileName, cacheSize: 1 << 20, pageSize: 1 << 13 });
+ expect(fd.pageSize).toBe(fdRef.pageSize);
+ expect(fd.maxPagesLoaded).toBe(fdRef.maxPagesLoaded);
+ await fd.close();
+ await fdRef.close();
+ });
+
+ it("mem descriptors keep their identity (data written through createNew stays on the caller's object)", async () => {
+ // regression: applying the fallbacks via a copy to a {type: "mem"}
+ // descriptor detached the memfile store from the caller's object,
+ // so a later readExisting(sameObject) found no data
+ const memSrc = { type: "mem" };
+ const fdW = await fastFile.createOverride(memSrc, 1 << 22, 1 << 16);
+ await fdW.write(new Uint8Array([1, 2, 3, 4]), 0);
+ await fdW.close();
+ expect(memSrc.data).toBeInstanceOf(Uint8Array);
+ const fdR = await fastFile.readExisting(memSrc, 1 << 22, 1 << 16);
+ const back = await fdR.read(4, 0);
+ expect(Array.from(back)).toEqual([1, 2, 3, 4]);
+ await fdR.close();
+ });
+
+ it("does not mutate the caller's descriptor object", async () => {
+ const src = { type: "file", fileName };
+ const fd = await fastFile.readExisting(src, 1 << 22, 1 << 16);
+ expect(src.cacheSize).toBe(undefined);
+ expect(src.pageSize).toBe(undefined);
+ await fd.close();
+ });
+});
diff --git a/test/test.js b/test/test.js
index 38da971..7195aaa 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,4 +1,4 @@
-import assert from "assert";
+import { expect } from "vitest";
import fs from "fs";
import * as fastFile from "../src/fastfile.js";
@@ -20,14 +20,13 @@ async function readBigInt(f, pos) {
const n8 = 32;
const buff = await f.read(n8, pos);
- assert(buff.byteLength == n8);
+ expect(buff.byteLength).toBe(n8);
return Scalar.fromRprLE(buff, 0);
}
describe("fastfile test", function () {
let fileName = "test.bin";
- this.timeout(1000000000);
const values = {};
it("should write a big file sequentially", async () => {
@@ -43,40 +42,15 @@ describe("fastfile test", function () {
});
it("should fail if trying to override", async () => {
- let throwed = false;
- try {
- await fastFile.createNoOverride(fileName);
- } catch (err) {
- throwed = true;
- }
- assert(throwed == true);
+ await expect(fastFile.createNoOverride(fileName)).rejects.toThrow();
});
it("trying to write a readonly File", async () => {
- let throwed = false;
- try {
+ await expect(async () => {
const f = await fastFile.readExisting(fileName);
await writeBigInt(f, Scalar.add(q,3), 0);
await f.close();
- } catch (err) {
- throwed = true;
- }
- assert(throwed == true);
- });
-
- it("should read the file", async () => {
- const f = await fastFile.readExisting(fileName);
- for (let i=0; i<1000000; i++) {
- const n = await readBigInt(f, i*32);
- if (Scalar.sub(n, q) != i) {
- console.log(f);
- console.log(Scalar.sub(n, q));
- console.log(i);
- }
- assert(Scalar.sub(n, q) == i);
- if ((i%100000) == 0) console.log("Reading: " + i);
- }
- await f.close();
+ }).rejects.toThrow();
});
it("should read the file", async () => {
@@ -88,7 +62,7 @@ describe("fastfile test", function () {
console.log(Scalar.sub(n, q));
console.log(i);
}
- assert(Scalar.sub(n, q) == i);
+ expect(Scalar.sub(n, q) == i).toBe(true);
if ((i%100000) == 0) console.log("Reading: " + i);
}
await f.close();
@@ -106,7 +80,7 @@ describe("fastfile test", function () {
} else {
expectedOldVal = Scalar.add(q,j);
}
- assert(Scalar.eq(expectedOldVal, oldVal));
+ expect(Scalar.eq(expectedOldVal, oldVal)).toBe(true);
const newVal = F.random();
values[j] = newVal;
// console.log("Start Writing", j);
@@ -137,7 +111,7 @@ describe("fastfile test", function () {
const vals = await Promise.all(ops);
for (let i=0; i resolve(root, ...parts);
+
+export default defineConfig(({ mode }) => {
+ const build = mode === "browser"
+ ? {
+ lib: {
+ entry: "./src/fastfile.browser.js",
+ name: "fastfile",
+ formats: ["es", "iife"],
+ fileName: (format) => format === "es" ? "browser.esm.js" : "browser.iife.js",
+ },
+ outDir: "build/browser",
+ emptyOutDir: true,
+ }
+ : {
+ lib: {
+ entry: "./src/fastfile.js",
+ formats: ["cjs"],
+ fileName: () => "main.cjs",
+ },
+ outDir: "build/node",
+ emptyOutDir: true,
+ rollupOptions: {
+ external: builtinModules,
+ },
+ };
+
+ return {
+ build,
+ test: {
+ projects: [
+ {
+ // Node — ESM source
+ test: {
+ name: "node-esm",
+ include: ["test/**/*.test.js"],
+ exclude: ["test/fastfile.browser.test.js", "test/idbcache.browser.test.js"],
+ environment: "node",
+ globals: true,
+ testTimeout: 100_000,
+ },
+ },
+ {
+ // Node — CJS build
+ test: {
+ name: "node-cjs",
+ include: [
+ "test/memfile.test.js",
+ "test/bigmemfile.test.js",
+ ],
+ environment: "node",
+ globals: true,
+ testTimeout: 100_000,
+ },
+ resolve: {
+ alias: [
+ {
+ find: abs("src/fastfile.js"),
+ replacement: abs("build/node/main.cjs"),
+ },
+ ],
+ },
+ },
+ {
+ // Browser — ESM source inside real Chromium via Playwright
+ test: {
+ name: "browser-esm",
+ include: ["test/fastfile.browser.test.js", "test/idbcache.browser.test.js"],
+ globals: true,
+ testTimeout: 100_000,
+ hookTimeout: 100_000,
+ browser: {
+ provider: playwright(),
+ enabled: true,
+ headless: true,
+ instances: [{ browser: "chromium" }],
+ },
+ },
+ },
+ ],
+ },
+ };
+});