diff --git a/.gitignore b/.gitignore index a46d06d84..facfd9e8a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,10 @@ yalc.lock # Perf tests .reassure + +# Benchmark output files +.bench-baseline.json +.bench-writebuffer.json +bench-results.html +cpp/build/ +cpp/build-wasm/ diff --git a/PROPOSAL.md b/PROPOSAL.md new file mode 100644 index 000000000..20e069d7c --- /dev/null +++ b/PROPOSAL.md @@ -0,0 +1,127 @@ +*Proposal:* Multi-Threaded Storage Engine for react-native-onyx + +*Background:* +*_Onyx who?_* +react-native-onyx is the backbone and beating heart of New Expensify. It drives both most of our state management and data persistence in the front-end. Onyx consists of three main layers: + +* *The In-Memory Cache.* Most of the data in Onyx is kept hot in an in-memory cache. Onyx operations such as `set`, `merge`, `mergeCollection`, or their combined for `update` synchronously update the cache and notify subscribers immediately. These functions also kick off an synchronous call to the persistence layer. +* *The Persistence Layer.* This layer is responsible for saving data to disk so it is stored offline and can be retrieved later. + * On web, it uses IndexedDB + * On iOS/Android, it uses react-native-nitro-sqlite. +* *The Subscription Layer.* This layer is responsible for tracking subscribers and propagating state changes across tabs and across the React tree. + +*_Onyx is single-threaded_* +JavaScript is generally single-threaded, so all of this happens in a single thread. This means that each time `Onyx.update` is called, we: + +* Update the cache +* Notify subscribers +* Persist the change to disk + +To be clear, this doesn't happen _synchronously_ with every call to `Onyx.update`. We have some batching mechanisms (for `Onyx.merge` only), and we notify subscribers optimistically from the cache before asynchronously persisting the change to disk. But it does all happen in a single thread - the same thread that also handles all React rendering and nearly all the rest of the app logic. This fundamentally means that CPU cycles spent on persistence can't be used for other work like React rendering. + +*_How Onyx merge works_* +`Onyx.merge()` is the most common write operation in the app. Each merge on IndexedDB follows a read-merge-write cycle: + +1. *Read* the full JSON blob from IndexedDB +2. *Deserialize* it in JavaScript +3. *Deep-merge* the patch into the full value +4. *Re-serialize* the entire merged value +5. *Write* the full blob back to IndexedDB + +For large objects (e.g. a report with hundreds of actions), this means reading and writing potentially hundreds of KB even when the patch is only a few bytes. This pattern applies to `merge()`, `multiMerge()`, `mergeCollection()`, and `update()` with merge operations. + +*_How Onyx keeps multiple tabs in sync_* + +Onyx's existing `InstanceSync` module (`lib/storage/InstanceSync/index.web.ts`) keeps multiple browser tabs in sync using the [`storage` event](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) on `localStorage`: + +1. When any storage write occurs (set, merge, remove, clear), the storage layer calls `InstanceSync.setItem(key)` (or the multi-key equivalent). +2. `InstanceSync` writes the changed key name to `localStorage` under a sentinel key (`SYNC_ONYX`), then immediately removes it. This `set` + `remove` cycle fires a `storage` event in other tabs (the `storage` event only fires in tabs *other* than the one that triggered it). +3. In each receiving tab, the `storage` event listener reads the key name from `event.newValue`, then calls `storage.getItem(key)` to fetch the updated value from IndexedDB. +4. The fetched value is passed to Onyx's `onStorageKeyChanged` callback, which updates the in-memory cache and notifies subscribers. + +This approach has several limitations: +- *One key per event*: Each `localStorage.setItem` fires a separate event, so a `multiSet` of N keys fires N events in every other tab, each triggering an IndexedDB read. +- *`localStorage` overhead*: The sentinel key is written to disk on every single storage operation, even though it is immediately removed. +- **No payload**: The `storage` event only carries the key name, not the value. Every receiving tab must independently re-read the full value from IndexedDB. + +*_Multithreading on the web_* +On the web platform, JS provides the [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) to perform tasks on background threads, rather than in the main thread. These APIs are mature but have some limitations. In particular, using [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer), the web API that allows memory to be directly shared between threads without copying, requires that your web app be [cross-origin isolated](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements), which almost certainly isn't feasible for Expensify in the near term. Our front-end interacts with multiple 3rd party origins, such as Plaid, Onfido, FullStory, and Sentry, and each of those origins would need to set the COOP/COEP headers and be cross-origin isolated as well. + +So practically the only way to share data between threads in JavaScript in New Expensify today is with `postMessage` - you send data from one thread and listen on the other with an `onmessage` event handler. You can pass most serializable data you want across (no functions, but most other types are fair game). That data gets passed via a structured clone, which has some overhead, but less overhead than serialization+deserialization. This data passing can be problematic if you aren't careful, because that structured cloning can be slower than just doing everything in the main thread. + +*_Multithreading on iOS/Android_* +On iOS/Android, the story is different. React Native is [architectured to run on two threads](https://reactnative.dev/architecture/threading-model), the JS thread where React runs and the main thread where the native C++/Swift/Kotlin code runs. They communicate with each other with low overhead using [Meta's JavaScriptInterface (JSI)](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/jsi/jsi/jsi.h). + +There are multiple module systems in the React Native ecosystem, but I'll be focusing on [NitroModules](https://nitro.margelo.com/), because it's the most performant, and in my opinion the easiest to understand in this context. The key building block is the [HybridObject](https://nitro.margelo.com/docs/hybrid-objects) - you define an object schema in TypeScript, and then [nitrogen](https://nitro.margelo.com/docs/nitrogen) generates rich C++ stucts for your schema at compile time, which you then fill in implementation details for. At runtime, you call `NitroModules.createHybridObject()` and you get a JS object with the TypeScript type you specify, but with the memory for that object automagically shared between JS and a native thread. The JS HybridObject can (synchronously or asynchronously) interact with the native thread with very low overhead. Furthermore, [HybridObjects are runtime-agnostic](https://nitro.margelo.com/docs/worklets): + +> Nitro itself is fully runtime-agnostic, which means every Hybrid Object can be used from any JS Runtime or Worklet Context. +> +> This allows the caller to call into native Nitro Modules from libraries like react-native-worklets-core, or react-native-reanimated. You can use a Nitro Hybrid Object on the default React JS context, on the UI context, or on any other background worklet context. + +This does not, however, imply that they are inherently thread-safe. Synchronization and locking must be handled in the C++ implemnetation you fill in. + +Thanks to JSI and NitroModules, it becomes possible to interact with native C++ APIs like `std::mutex` to do synchronized work across threads without the overhead of structured cloning or message passing. + +There are several ways to create "worker threads" in React Native: + +- Native C++ threads can be spawned with `std::thread`. +- [react-native-worklets](https://docs.swmansion.com/react-native-worklets/docs/) provides a convenient method to spawn JS runtimes in separate threads. We already use this in E/App, because it's the underlying core mechanic used in [Reanimated](https://docs.swmansion.com/react-native-reanimated/). + +*Problem:* When storage operations happen on the main thread, if a user has high traffic or data volume, then the main thread gets jammed up persisting data, which slows down rendering, interactions, and just about everything else, which in turn prevents users from experiencing the app as snappy and responsive. + +*Solution:* + +1. Create a `WriteBuffer` that sits between the main Onyx API and the persistence layer. The `WriteBuffer` will: + - Track two types of pending entries per key: + - *`SET` entries*: Full value replacements (from `set()`, `multiSet()`, `setCollection()`). If a key already has a pending write (of any type), a new `SET` replaces it entirely. + - *`MERGE` entries*: Patch deltas (from `merge()`, `multiMerge()`, `mergeCollection()`). If a key already has a pending `MERGE`, the new patch is `fastMerge`'d into the existing pending patch. If it has a pending `SET`, the merge is applied to the full value instead. + - Periodically flush writes to the persistence layer + - The storage provider receives already-coalesced operations, reducing the total number of I/O operations + - In the (rare) even that there's a cache miss in the cache layer and Onyx needs to read data from disk, the WriteBuffer is checked first: + - *If there's a pending `SET` entry*: The full value is returned immediately from memory without hitting the provider. + - *If there's a pending `MERGE` entry*: The WriteBuffer is flushed first, ensuring the provider has the correct merged value on disk, then the read proceeds normally. + - *If there's no pending entry*: The read goes straight to the provider. + - _Note:_ In practice this path is rarely (never?) hit because Onyx's in-memory cache (which sits above the WriteBuffer) handles most reads without reaching the storage layer. It's unclear in what scenario data could be missing from the cache _and_ have a pending write, but it's probably best to plug this correctness gap/potential race condition from the get-go. + - The storage and flushing behavior of the `WriteBuffer` will be implemented differently on web vs native, with a consistent interface we'll call `BufferStore`. +2. Move the Onyx persistence layer to a worker thread. + - On both platforms, a worker thread wraps the persistence layer, keeping that layer storage-provider-agnostic + - On web, we use web workers and `postMessage` to spawn and communicate with the worker thread. + - On native, we use react-native-worklets to spawn and communicate with the worker thread. + - The `BufferStore` data storage: + - On web, keeps the `WriteBuffer` data as a pure JS `Map` + - On native, keeps the `WriteBuffer` as a thread-safe NitroModules `HybridObject` with memory shared across threads. The underlying C++ implementation will use `std::mutex`, `shared_lock`, and `unique_lock` to coordinate thread safety. + - The `BufferStore` flush scheduling: + - On web, the main thread uses `requestIdleCallback` with a max 200ms timeout to schedule flush. It uses `postMessage` with raw JS objects, which does a structured clone to pass the data to a worker thread. + - On native, the main thread never flushes. It just populates the `BufferStore` in shared memory and then the worker thread handles periodic flushing. + - The `BufferStore` flush implementation in the worker thread: + - On web: + 1. accepts the data with an `onmessage` listener + 2. Serializes it to JSON with `JSON.serialize()` + 3. Persists it (storage provider agnostic) + 4. Broadcasts the data to other tabs with `BroadcastChannel` (more on this later) + - On native: + 1. Clears the HybridObject. Under the hood, this calls Nitro's `toJSI` to create a JS object on the worker runtime, which is very fast. + 2. Serializes it to JSON with `JSON.serialize()` + 3. Persists it (storage provider agnostic) +3. (web only) Refactor `InstanceSync` to accept write changes from other tabs: + - When the `WriteBuffer` is flushed in the "leader tab", we no longer pass just modified keys, but the structured JS buffered writes. + - `InstanceSync` will perform those buffered writes directly, updating the cache and notifying subscribers. No storage I/O needed. +4. (web only) Make the official SQLite wasm build the default storage provider on the web. + - This allows us to leverage SQLite's built-in `JSON_PATCH` utilities to merge data, avoiding the `read` -> `deserialize` -> `merge` -> `serialize` -> `write` paradigm we have with `IndexedDB`. + - Apples-to-Apples, SQLite WASM [signficantly outperforms](https://haroonwaves.com/blog/building-email-client) IndexedDB. It requires using a worker thread, which is why it wasn't an "automatic" performance improvement when we tried it in the past. But paired with cleverly buffered writes and throttled flush, we can get the performance benefits from SQLite WASM. + - This also unlocks other kinds of future optimizations to the persistence layer, consistently across web and native. + +*Benchmarks and results:* + +Benchmark run in a _real browser environment_ (headless Chromium via Playwright) using Vitest in browser mode, with tinybench for statistical rigor. + +Data generators attempt to create production-realistic Onyx data (reports, transactions) at four scales: + +- Small (50 reports, 50 transactions) +- Modest (250 reports, 250 transactions) +- Heavy (1000 reports, 1000 transactions) +- Extreme (5000 reports, 5000 transactions) + +Currently, the benchmarks measure throughput of Onyx methods such as `Onyx.set`, `Onyx.merge`, and `Onyx.mergeCollection` on the main thread. They do not capture metrics from the worker thread(s), because slowness on the main thread is the main problem we seek to solve. + +[The results speak for themselves](https://lighthearted-otter-b9124d.netlify.app/) - *~98% improvement in Onyx.update throughput in the Heavy and Extreme tiers* diff --git a/PROPOSAL_DRAFT.md b/PROPOSAL_DRAFT.md new file mode 100644 index 000000000..8e6ab145f --- /dev/null +++ b/PROPOSAL_DRAFT.md @@ -0,0 +1,327 @@ +# Proposal: Multi-Threaded Storage Engine for react-native-onyx + +## Problem Statement + +Onyx is the client-side data persistence and state management layer used across the Expensify App on all platforms (web, iOS, Android). It provides an offline-first, reactive key-value store that synchronizes with the backend. + +The current storage architecture has several problems that become increasingly costly at scale: + +### 1. The read-merge-write pattern is expensive for merge operations + +`Onyx.merge()` is the most common write operation in the app. On IndexedDB (web), each merge follows a read-merge-write cycle: read the full JSON blob, deserialize it, deep-merge the patch, re-serialize, and write the full blob back. For large objects (e.g. a report with hundreds of actions), this means reading and writing potentially hundreds of KB even when the patch is only a few bytes. + +### 2. Every write blocks the main thread and hits storage immediately + +When a write is issued, the storage call is made immediately. While IndexedDB itself is asynchronous, the JS thread still bears the cost of serializing the data and managing the transaction. Rapid successive writes to the same key each independently go through this full cycle, even when intermediate values are never read back. + +### 3. Divergent storage implementations across platforms + +On iOS and Android, Onyx uses SQLite via `react-native-nitro-sqlite`. On web, it uses IndexedDB (`idb-keyval`). The native implementation has separate SQL queries, and web has no SQL at all. Bug fixes and optimizations apply to one platform but not the other. + +### 4. No shared code between platforms + +The native and web storage providers are completely separate codebases. This duplication makes maintenance expensive and means improvements must be implemented twice. + +--- + +## Proposed Solution + +This refactor introduces a **multi-threaded storage engine** with a symmetric "JS worker thread" pattern on both platforms. The architecture has three layers: + +### Layer 1: WriteBuffer (TypeScript, Main Thread, All Platforms) + +A `WriteBuffer` sits between Onyx's cache layer and the storage provider. It intercepts all writes and stages them in memory before flushing to the persistence layer in batches. + +The WriteBuffer tracks two types of pending entries per key: +- **`SET` entries**: Full value replacements. A new `SET` replaces any pending entry entirely. +- **`MERGE` entries**: Patch deltas. Successive merges are coalesced via `fastMerge`. A merge after a SET applies the patch to the full value in-memory. + +The WriteBuffer's backing data structure is modular via the `BufferStore` interface: +- **Web**: `BufferStore/index.ts` -- a simple JS `Map`. On flush, entries are serialized and sent to a Web Worker via `postMessage`. +- **Native (iOS/Android)**: `BufferStore/index.native.ts` -- a NitroModules `HybridObject` wrapping a mutex-protected C++ `AnyMap`. JS objects are converted to `AnyValue` via NitroModules' `JSIConverter` at zero-copy cost (no `JSON.stringify` on the main thread). A Worklet Worker Runtime drains this shared buffer, serializes entries on the background thread, and persists via SQLite. + +Read-through ensures cache consistency: pending `SET` entries are served from memory; pending `MERGE` entries trigger a flush before reading from the provider. + +### Layer 2: Shared SQL Queries + Official SQLite Packages + +Rather than maintaining a custom C++ SQLite wrapper and WASM build, we leverage **official, battle-tested SQLite packages**: + +- **Web**: `@sqlite.org/sqlite-wasm` with `opfs-sahpool` VFS for OPFS-backed persistence +- **Native (iOS/Android)**: `react-native-nitro-sqlite` with synchronous APIs for maximum throughput from the worker thread + +Both platforms share a single source of truth for all SQL queries: `SQLiteQueries.ts`. This file contains all `CREATE TABLE`, `INSERT`, `UPDATE`, `DELETE`, and `PRAGMA` statements. + +Key SQL operations: +- `SET`: `REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));` +- `MERGE`: `INSERT ... ON CONFLICT DO UPDATE SET valueJSON = JSON_PATCH(valueJSON, JSON(?));` (atomic, no read-merge-write) +- `REMOVE`: `DELETE FROM keyvaluepairs WHERE record_key = ?;` +- Batch writes execute in a single transaction for atomicity + +### Layer 3: Symmetric JS Worker Threads + +Both platforms use a dedicated JS background thread for persistence, achieving a symmetric architecture: + +**Web:** A standard Web Worker (`lib/storage/worker.ts`) receives batched writes from the main thread via `postMessage`. It dynamically imports either `@sqlite.org/sqlite-wasm` (for OPFS-capable browsers) or `IDBKeyValProvider` (fallback for older browsers). After persisting, the worker broadcasts value-bearing messages over `BroadcastChannel` for cross-tab sync. + +**Native (iOS/Android):** A `react-native-worklets-core` Worker Runtime (`lib/storage/NativeFlushWorker.ts`) runs on a background JS thread. It periodically drains the shared `HybridObject` buffer (shared memory, no `postMessage` overhead), `JSON.stringify`s the entries off the main thread, and calls `react-native-nitro-sqlite`'s synchronous APIs to persist to SQLite. + +### Cross-Tab Synchronization (Web Only) + +After persisting a batch, the worker broadcasts **value-bearing messages** over `BroadcastChannel('onyx-sync')`. `InstanceSync` on each receiving tab's main thread handles incoming messages: +- `set`: `onStorageKeyChanged(key, value)` directly -- no storage read +- `merge`: `fastMerge(cachedValue, patch)` against the local cache (fallback to `provider.getItem` if not cached) +- `remove`: `onStorageKeyChanged(key, null)` +- `clear`: notify all cached keys with null + +--- + +## Architecture Overview + +```mermaid +graph TD + subgraph mainThread [Main Thread -- All Platforms] + Onyx["Onyx.set / Onyx.merge / useOnyx"] + Cache["OnyxCache.set + notify subscribers"] + WB["WriteBuffer (TypeScript): coalescing via fastMerge"] + Store["BufferStore interface"] + Onyx --> Cache + Onyx --> WB + WB --> Store + end + + subgraph storeImpl [BufferStore Implementation] + JSMap["Web: BufferStore/index.ts (JS Map)"] + HybridBS["Native: BufferStore/index.native.ts (NitroModules AnyMap + shared_mutex)"] + end + + Store --> JSMap + Store --> HybridBS + + subgraph webPath [Web: requestIdleCallback flush] + WebFlush["drain JS Map, postMessage(JS objects via structured clone)"] + JSMap --> WebFlush + end + + subgraph webWorker [Web Worker] + Worker["worker.ts: JSON.stringify + persist"] + SQLiteWeb["@sqlite.org/sqlite-wasm + opfs-sahpool VFS"] + IDBFallback["Fallback: IDBKeyValProvider"] + BChan["BroadcastChannel"] + WebFlush -->|"structured clone"| Worker + Worker -->|"OPFS available"| SQLiteWeb + Worker -->|"no OPFS"| IDBFallback + Worker --> BChan + end + + subgraph nativePath [Native Worklet Worker] + WorkletRT["NativeFlushWorker (react-native-worklets-core)"] + SQLiteNative["react-native-nitro-sqlite (sync APIs)"] + HybridBS -.->|"shared memory drain()"| WorkletRT + WorkletRT -->|"JSON.stringify on worker"| SQLiteNative + end + + subgraph otherTab [Other Tab Main Thread -- Web Only] + IS["InstanceSync receiver"] + Cache2["OnyxCache + subscribers"] + BChan --> IS + IS --> Cache2 + end +``` + +### Data Flow: Native (iOS/Android) + +``` +JS Main Thread Worklet Worker Runtime +-------------- ---------------------- +Onyx.set(key, value) + -> cache.set(key, value) + -> subscribers notified + -> writeBuffer.set(key, value) + -> [TS coalescing via fastMerge] + -> bufferStore.set(key, entry) + -> [NitroModules fromJSI: AnyValue conversion, NOT JSON] + -> [C++: shared_mutex unique_lock, insert, unlock] + -> return (fire-and-forget) + ...flush interval fires... + drain() shared HybridObject buffer + -> [C++: shared_mutex unique_lock, swap, unlock] + [NitroModules toJSI: AnyValue -> JS objects] + JSON.stringify entries (on worker thread!) + nativeSQLiteProvider.multiSet() (sync API) + nativeSQLiteProvider.multiMerge() (sync API) +``` + +### Data Flow: Web + +``` +Main Thread Web Worker +----------- ---------- +Onyx.set(key, value) + -> cache.set(key, value) + -> subscribers notified + -> writeBuffer.set(key, value) + -> [TS coalescing via fastMerge] + -> jsMap.set(key, entry) + -> return (fire-and-forget) + + ...requestIdleCallback fires... + -> writeBuffer.flushNow() + -> drain JS Map + -> postMessage(JS objects) onmessage (structured clone) + JSON.stringify entries (on worker!) + provider.multiSet(batch) + provider.multiMerge(batch) + BroadcastChannel.postMessage({type, values}) +``` + +--- + +## Key Files + +### Shared SQL Queries + +| File | Description | +|------|-------------| +| `lib/storage/providers/SQLiteQueries.ts` | Single source of truth for all SQL: CREATE TABLE, INSERT, UPDATE, DELETE, PRAGMA. Used by both web and native SQLite providers. | + +### C++ (Native Only) + +| File | Description | +|------|-------------| +| `cpp/NativeBufferStore.h` / `.cpp` | `std::shared_mutex`-protected `AnyMap` HybridObject. Pure buffer -- no threading, no SQLite. Provides `set`, `get`, `drain`, `entries`, `clear`. | +| `cpp/CMakeLists.txt` | CMake build for the NativeBufferStore library and its tests | +| `cpp/test_native_buffer_store.cpp` | Unit tests for thread-safe buffer operations | + +### TypeScript (Shared) + +| File | Description | +|------|-------------| +| `lib/storage/WriteBuffer.ts` | Write coalescing with pluggable `BufferStore` and `FlushScheduler` | +| `lib/storage/BufferStore/types.ts` | `BufferStore` interface | +| `lib/storage/BufferStore/index.ts` | Web: JS `Map` wrapper | +| `lib/storage/BufferStore/index.native.ts` | Native: NitroModules HybridObject (with JS Map fallback) | +| `lib/storage/index.ts` | Main storage API with WriteBuffer integration | + +### Web Worker + +| File | Description | +|------|-------------| +| `lib/storage/worker.ts` | Unified web worker: dynamically loads SQLite WASM or IDB backend, handles all storage ops, broadcasts value-bearing cross-tab messages | +| `lib/storage/WorkerStorageProvider.ts` | Main-thread proxy: postMessage-based request/response to the worker | +| `lib/storage/providers/SQLiteProvider/index.web.ts` | `@sqlite.org/sqlite-wasm` with `opfs-sahpool` VFS, prepared statements | + +### Native Worker + +| File | Description | +|------|-------------| +| `lib/storage/NativeFlushWorker.ts` | `react-native-worklets-core` Worker Runtime: periodic drain + JSON.stringify + nitro-sqlite persistence | +| `lib/storage/providers/SQLiteProvider/index.native.ts` | `react-native-nitro-sqlite` with synchronous APIs for worker-thread usage | +| `lib/storage/platforms/index.native.ts` | Wires HybridObject BufferStore with NativeFlushWorker | + +### Cross-tab sync + +| File | Description | +|------|-------------| +| `lib/storage/InstanceSync/index.web.ts` | BroadcastChannel receiver: handles value-bearing set/merge/remove/clear messages | + +--- + +## What Gets Replaced (from baseline) + +| Old | New | +|-----|-----| +| Single-threaded IDB writes on main thread | WriteBuffer + Web Worker with batched persistence | +| Key-only cross-tab broadcasts (requiring storage reads) | Value-bearing BroadcastChannel messages | +| Platform-divergent SQL queries | Shared `SQLiteQueries.ts` | +| No write coalescing | `WriteBuffer` with SET/MERGE entry coalescing via `fastMerge` | + +## What Gets Kept + +| File | Reason | +|------|--------| +| `react-native-nitro-sqlite` | Official native SQLite package, called from worker thread | +| `@sqlite.org/sqlite-wasm` | Official web SQLite WASM package with OPFS VFS | +| `lib/storage/providers/IDBKeyValProvider/` | Retained as fallback for browsers without OPFS | +| `lib/OnyxCache.ts` | In-memory cache stays in JS on the main thread | +| `lib/storage/InstanceSync/index.web.ts` | Receiver unchanged, already handles value-bearing messages | +| `lib/storage/providers/types.ts` | `StorageProvider` interface stays | + +## New Dependencies + +| Package | Purpose | Scope | +|---------|---------|-------| +| `react-native-worklets-core` | Background JS Worker Runtime for native platforms | Peer dependency (native only) | + +--- + +## Benchmarking + +Benchmarks run in **real browser environments** (headless Chromium via Playwright) using Vitest in browser mode with tinybench. Data generators create production-realistic Expensify data (reports, transactions) at four scale tiers (50, 250, 1000, 5000 keys). + +The unified architecture will be benchmarked against the current implementation on all three platforms (web, iOS, Android) to validate performance gains from: +- Write coalescing (reducing total storage operations) +- Off-main-thread JSON serialization (native) +- Batched SQLite transactions +- Value-bearing cross-tab broadcasts (eliminating redundant reads) + +--- + +## How to Build + +### Native (iOS/Android) -- C++ Buffer Tests + +```bash +cd cpp +mkdir -p build && cd build +cmake .. -DBUILD_TESTING=ON +make -j8 +./native_buffer_store_test # Thread-safe buffer tests +``` + +### TypeScript Tests + +```bash +npm install +npm test +``` + +### Benchmarks + +```bash +# Run benchmarks in headless Chromium +npx vitest bench --run --config vitest.bench.config.ts --outputJson bench-results/current.json + +# Generate comparison report +npx tsx scripts/generateBenchReport.ts bench-results/baseline.json bench-results/current.json --open +``` + +--- + +## Future Optimizations + +### Glaze-based JSON Serialization in a Native C++ Worker Thread + +The current architecture performs `JSON.stringify` in the Worklet Worker Runtime (a JS background thread). A further optimization would be to move JSON serialization entirely into C++ using [Glaze](https://github.com/stephenberry/glaze), a high-performance C++ JSON library. + +This would enable: +1. **True native C++ worker thread** (not a JS runtime) for persistence +2. **Zero-copy JSON serialization** from `AnyValue` to SQLite-ready strings in C++ +3. **Shared C++ worker code across all platforms** -- including web via WASM compilation +4. **Elimination of `react-native-nitro-sqlite`** in favor of a direct C++ SQLite wrapper using the SQLite C API, enabling a single SQLite provider implementation for iOS, Android, and web + +This optimization was deferred because it requires: +- Building and maintaining a custom SQLite WASM module with Emscripten (including OPFS VFS) +- Writing C++ bindings for `AnyValue` to Glaze's reflection system +- More complex build toolchain (Emscripten SDK for web, CMake for native) + +The current architecture is designed to make this migration straightforward: the `SQLiteQueries.ts` file already defines all SQL as platform-agnostic constants, and the `BufferStore` HybridObject pattern cleanly separates the buffer from the persistence layer. + +--- + +## Open Questions + +1. **`react-native-worklets-core` compatibility**: Verify the Worklet Worker Runtime can access `react-native-nitro-sqlite` synchronous APIs and that the NitroModules HybridObject is accessible from the worker context. +2. **AnyValue thread safety with NitroModules**: Confirmed that `AnyValue` is a deep-copied C++ value type, safe to pass between threads. The `NativeBufferStore` uses `std::shared_mutex` for concurrent access (shared locks for reads, unique locks for writes). +3. **`flushNow()` on shutdown**: On native, `flushNow()` synchronously drains and executes SQL. On web `beforeunload`, verify time budgets. +4. **OPFS availability**: Modern browsers support OPFS; the architecture gracefully falls back to IDB when OPFS is unavailable. +5. **Nitro module packaging**: Standalone package vs embedded in `react-native-onyx`. diff --git a/README.md b/README.md index e5384e8dc..64b7852ad 100644 --- a/README.md +++ b/README.md @@ -510,3 +510,105 @@ you to edit the Onyx source directly in the Onyx repo, and have those changes ho Now you can make changes directly to the `react-native-onyx` source code and your React Native project should-hot reload with those changes in realtime. _Note:_ If you want to unlink `react-native-onyx`, simply run `npm install` from your React Native project directory again. That will reinstall `react-native-onyx` from npm. + +# Benchmarks + +The `benchmarks/` directory contains a browser-based benchmark suite that measures the performance of core Onyx operations using real IndexedDB in a headless Chromium browser. This gives accurate measurements that reflect production web behavior, unlike Jest-based tests which use mocked storage. + +## What's benchmarked + +Every perf-sensitive Onyx method is covered: + +| Method | File | +|---|---| +| `set()`, `multiSet()`, `setCollection()` | `benchmarks/set.bench.ts` | +| `merge()`, `mergeCollection()`, `update()` | `benchmarks/merge.bench.ts` | +| `connect()`, `disconnect()`, subscriber notifications | `benchmarks/connect.bench.ts` | +| `init()` | `benchmarks/init.bench.ts` | +| `clear()` | `benchmarks/clear.bench.ts` | + +Each benchmark runs across four data tiers to show how operations scale: + +| Tier | Reports | Report Actions | Transactions | +|---|---|---|---| +| **small** | 50 | 500 | 50 | +| **modest** | 250 | 2,500 | 250 | +| **heavy** | 1,000 | 10,000 | 1,000 | +| **extreme** | 5,000 | 50,000 | 5,000 | + +## Running benchmarks + +```bash +# Run all benchmarks +npm run bench + +# Run a specific benchmark file +npx vitest bench --config vitest.bench.config.ts benchmarks/set +``` + +## Comparing branches + +To measure the performance impact of a change, use the comparison workflow: + +```bash +# Compare current branch against main (automated) +npm run bench:compare + +# Compare against a different base branch +npm run bench:compare -- some-branch + +# Compare only specific benchmarks +npm run bench:compare -- main -- benchmarks/set +``` + +This checks out the base branch, runs benchmarks to capture a baseline, switches back, and runs again with `--compare` to show the diff: + +``` +· Onyx.merge() - partial update 250 reports 21.46 hz [0.95x] ⇓ + Onyx.merge() - partial update 250 reports 22.58 hz (baseline) +``` + +You can also save and compare manually: + +```bash +# Save current results as baseline +npm run bench:save + +# ...make changes... + +# Compare against saved baseline +npx vitest bench --config vitest.bench.config.ts --compare .bench-baseline.json +``` + +## HTML benchmark reports + +For a visual, color-coded comparison of benchmark results, use the report scripts: + +```bash +# Run benchmarks and generate an HTML report (opens in browser) +npm run bench:report + +# Compare current branch vs main with a visual report +npm run bench:report:compare main + +# Don't auto-open the browser +./scripts/benchAndReport.sh --no-open + +# Compare multiple configurations (e.g. different storage providers) +./scripts/benchAndReport.sh \ + --run "SQLite (default)" \ + --run "IDB only:printf 'import W from \"../providers/IDBKeyValProvider\";\nexport default W;\n' > lib/storage/platforms/index.ts" +``` + +The report generator can also be used standalone on previously-captured JSON files: + +```bash +# Generate a comparison report from saved JSON files +npx tsx scripts/generateBenchReport.ts baseline.json current.json \ + --labels "Baseline,Current" -o bench-results.html --open +``` + +The generated HTML uses green/red highlighting: +- **Green** = faster (improvement >= 5% and >= 1ms absolute) +- **Red** = slower (regression >= 5% and >= 1ms absolute) +- **Gray** = negligible change diff --git a/bench-results-comparison.html b/bench-results-comparison.html new file mode 100644 index 000000000..c0231d899 --- /dev/null +++ b/bench-results-comparison.html @@ -0,0 +1,101 @@ + + + + +Onyx Benchmark Results + + + +

Onyx Benchmark Results

+

Generated 2/9/2026, 11:53:09 PM

+
+All values are mean time in milliseconds (lower is better). +Green = faster (improvement, ≥5% and ≥1ms) +Red = slower (regression, ≥5% and ≥1ms) +Gray = negligible +⚠ = unreliable (high variance, few samples) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationBaseline (IDB only)DM+IDB (prev)DM+SQLite (prev)DM+IDB (new)DM+SQLite (new)
Onyx.set()
Small (50 reports, 50 txns)6764.90 (-99%)4.93 (-99%)4.94 (-99%)4.96 (-99%)
Modest (250 reports, 250 txns)75.44.71 (-94%)4.67 (-94%)4.70 (-94%)4.71 (-94%)
Heavy (1000 reports, 1000 txns)4906.01 (-99%)6.00 (-99%)5.62 (-99%)5.66 (-99%)
Extreme (5000 reports, 5000 txns)602335.5 (-99%)36.0 (-99%)32.4 (-99%)32.3 (-99%)
Onyx.multiSet()
Small (50 reports, 50 txns)82.76.15 (-93%)6.17 (-93%)6.05 (-93%)6.10 (-93%)
Modest (250 reports, 250 txns)63014.4 (-98%)14.5 (-98%)14.2 (-98%)14.1 (-98%)
Heavy (1000 reports, 1000 txns)217953.6 (-98%)55.2 (-97%)52.1 (-98%)52.7 (-98%)
Extreme (5000 reports, 5000 txns)10939223 (-98%)249 (-98%)228 (-98%)241 (-98%)
Onyx.setCollection()
Small (50 reports, 50 txns)11.74.53 (-61%)4.58 (-61%)4.84 (-59%)4.61 (-61%)
Modest (250 reports, 250 txns)89.85.75 (-94%)5.98 (-93%)5.82 (-94%)5.66 (-94%)
Heavy (1000 reports, 1000 txns)4099.52 (-98%)9.22 (-98%)8.66 (-98%)8.90 (-98%)
Extreme (5000 reports, 5000 txns)225973.0 (-97%)189 (-92%) 180 (-92%) 192 (-91%)
Onyx.merge()
Small (50 reports, 50 txns)19.74.76 (-76%)4.77 (-76%)4.81 (-76%)4.75 (-76%)
Modest (250 reports, 250 txns)1064.59 (-96%)4.59 (-96%)4.84 (-95%)4.52 (-96%)
Heavy (1000 reports, 1000 txns)6535.80 (-99%)5.65 (-99%)5.39 (-99%)5.65 (-99%)
Extreme (5000 reports, 5000 txns)249128.4 (-99%)26.3 (-99%)30.1 (-99%)25.4 (-99%)
Onyx.mergeCollection()
Small (50 reports, 50 txns)17.84.79 (-73%)4.80 (-73%)4.93 (-72%)4.81 (-73%)
Modest (250 reports, 250 txns)97.310.8 (-89%)5.96 (-94%)5.60 (-94%)5.94 (-94%)
Heavy (1000 reports, 1000 txns)71510.6 (-99%)11.8 (-98%)9.97 (-99%)11.0 (-98%)
Extreme (5000 reports, 5000 txns)195248.0 (-98%)34.3 (-98%)31.8 (-98%)35.9 (-98%)
Onyx.update()
Small (50 reports, 50 txns)20.84.95 (-76%)4.88 (-77%)4.99 (-76%)4.91 (-76%)
Modest (250 reports, 250 txns)1275.85 (-95%)6.15 (-95%)5.45 (-96%)6.30 (-95%)
Heavy (1000 reports, 1000 txns)52810.1 (-98%)9.52 (-98%)9.02 (-98%)9.41 (-98%)
Extreme (5000 reports, 5000 txns)195853.3 (-97%)43.8 (-98%)41.7 (-98%)42.4 (-98%)
Onyx.connect() - register subscribers
Small (50 reports, 50 txns)0.0750.065 (-13%)0.099 (+33%)0.086 (+16%)0.104 (+40%)
Modest (250 reports, 250 txns)0.3580.354 (-1%)0.408 (+14%)0.546 (+52%)0.419 (+17%)
Heavy (1000 reports, 1000 txns)1.571.52 (-4%)3.16 (+101%)6.35 (+304%)3.45 (+120%)
Extreme (5000 reports, 5000 txns)10.78.23 (-23%)31.9 (+198%)9.71 (-9%)33.2 (+211%)
Onyx.connect() - collection subscriber
Small (50 reports, 50 txns)4.294.57 (+7%)4.91 (+14%)4.51 (+5%)4.85 (+13%)
Modest (250 reports, 250 txns)4.334.51 (+4%)4.82 (+11%)4.54 (+5%)4.56 (+5%)
Heavy (1000 reports, 1000 txns)4.564.58 (+0%)4.73 (+4%)4.55 (-0%)4.75 (+4%)
Extreme (5000 reports, 5000 txns)4.744.38 (-7%)4.80 (+1%)102 (+2054%)4.76 (+1%)
Notification throughput
Small (50 reports, 50 txns)114113 (-1%)117 (+2%)109 (-5%)111 (-3%)
Modest (250 reports, 250 txns)123118 (-5%)117 (-5%)112 (-9%)114 (-7%)
Heavy (1000 reports, 1000 txns)124121 (-2%)119 (-3%)112 (-10%)122 (-1%)
Extreme (5000 reports, 5000 txns)129122 (-6%)116 (-11%)125 (-3%)116 (-10%)
Onyx.init()
Small (50 reports, 50 txns)69.17.74 (-89%)4.10 (-94%)3.27 (-95%)4.10 (-94%)
Modest (250 reports, 250 txns)71.022.4 (-68%)22.0 (-69%)21.0 (-70%)21.9 (-69%)
Heavy (1000 reports, 1000 txns)24690.0 (-63%)91.1 (-63%)86.1 (-65%)94.5 (-62%)
Extreme (5000 reports, 5000 txns)1422413 (-71%)410 (-71%)384 (-73%)392 (-72%)
Onyx.clear()
Small (50 reports, 50 txns)0.3000.184 (-39%)0.175 (-41%)0.108 (-64%)0.189 (-37%)
Modest (250 reports, 250 txns)0.2750.139 (-49%)0.149 (-46%)0.107 (-61%)0.139 (-49%)
Heavy (1000 reports, 1000 txns)58.10.174 (-100%)0.191 (-100%)0.112 (-100%)0.180 (-100%)
Extreme (5000 reports, 5000 txns)72663.2 (-91%) 72.0 (-90%) 0.159 (-100%)68.2 (-91%)
+ + \ No newline at end of file diff --git a/bench-results.html b/bench-results.html new file mode 100644 index 000000000..b039fb6c9 --- /dev/null +++ b/bench-results.html @@ -0,0 +1,101 @@ + + + + +Onyx Benchmark Results + + + +

Onyx Benchmark Results

+

Generated 2/9/2026, 11:12:29 PM

+
+All values are mean time in milliseconds (lower is better). +Green = faster (improvement, ≥5% and ≥1ms) +Red = slower (regression, ≥5% and ≥1ms) +Gray = negligible +⚠ = unreliable (high variance, few samples) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationBaseline (IDB only)DM+IDBDM+SQLite
Onyx.set()
Small (50 reports, 50 txns)6764.90 (-99%)4.93 (-99%)
Modest (250 reports, 250 txns)75.44.71 (-94%)4.67 (-94%)
Heavy (1000 reports, 1000 txns)4906.01 (-99%)6.00 (-99%)
Extreme (5000 reports, 5000 txns)602335.5 (-99%)36.0 (-99%)
Onyx.multiSet()
Small (50 reports, 50 txns)82.76.15 (-93%)6.17 (-93%)
Modest (250 reports, 250 txns)63014.4 (-98%)14.5 (-98%)
Heavy (1000 reports, 1000 txns)217953.6 (-98%)55.2 (-97%)
Extreme (5000 reports, 5000 txns)10939223 (-98%)249 (-98%)
Onyx.setCollection()
Small (50 reports, 50 txns)11.74.53 (-61%)4.58 (-61%)
Modest (250 reports, 250 txns)89.85.75 (-94%)5.98 (-93%)
Heavy (1000 reports, 1000 txns)4099.52 (-98%)9.22 (-98%)
Extreme (5000 reports, 5000 txns)225973.0 (-97%)189 (-92%)
Onyx.merge()
Small (50 reports, 50 txns)19.74.76 (-76%)4.77 (-76%)
Modest (250 reports, 250 txns)1064.59 (-96%)4.59 (-96%)
Heavy (1000 reports, 1000 txns)6535.80 (-99%)5.65 (-99%)
Extreme (5000 reports, 5000 txns)249128.4 (-99%)26.3 (-99%)
Onyx.mergeCollection()
Small (50 reports, 50 txns)17.84.79 (-73%)4.80 (-73%)
Modest (250 reports, 250 txns)97.310.8 (-89%)5.96 (-94%)
Heavy (1000 reports, 1000 txns)71510.6 (-99%)11.8 (-98%)
Extreme (5000 reports, 5000 txns)195248.0 (-98%)34.3 (-98%)
Onyx.update()
Small (50 reports, 50 txns)20.84.95 (-76%)4.88 (-77%)
Modest (250 reports, 250 txns)1275.85 (-95%)6.15 (-95%)
Heavy (1000 reports, 1000 txns)52810.1 (-98%)9.52 (-98%)
Extreme (5000 reports, 5000 txns)195853.3 (-97%)43.8 (-98%)
Onyx.connect() - register subscribers
Small (50 reports, 50 txns)0.0750.065 (-13%)0.099 (+33%)
Modest (250 reports, 250 txns)0.3580.354 (-1%)0.408 (+14%)
Heavy (1000 reports, 1000 txns)1.571.52 (-4%)3.16 (+101%)
Extreme (5000 reports, 5000 txns)10.78.23 (-23%)31.9 (+198%)
Onyx.connect() - collection subscriber
Small (50 reports, 50 txns)4.294.57 (+7%)4.91 (+14%)
Modest (250 reports, 250 txns)4.334.51 (+4%)4.82 (+11%)
Heavy (1000 reports, 1000 txns)4.564.58 (+0%)4.73 (+4%)
Extreme (5000 reports, 5000 txns)4.744.38 (-7%)4.80 (+1%)
Notification throughput
Small (50 reports, 50 txns)114113 (-1%)117 (+2%)
Modest (250 reports, 250 txns)123118 (-5%)117 (-5%)
Heavy (1000 reports, 1000 txns)124121 (-2%)119 (-3%)
Extreme (5000 reports, 5000 txns)129122 (-6%)116 (-11%)
Onyx.init()
Small (50 reports, 50 txns)69.17.74 (-89%)4.10 (-94%)
Modest (250 reports, 250 txns)71.022.4 (-68%)22.0 (-69%)
Heavy (1000 reports, 1000 txns)24690.0 (-63%)91.1 (-63%)
Extreme (5000 reports, 5000 txns)1422413 (-71%)410 (-71%)
Onyx.clear()
Small (50 reports, 50 txns)0.3000.184 (-39%)0.175 (-41%)
Modest (250 reports, 250 txns)0.2750.139 (-49%)0.149 (-46%)
Heavy (1000 reports, 1000 txns)58.10.174 (-100%)0.191 (-100%)
Extreme (5000 reports, 5000 txns)72663.2 (-91%) 72.0 (-90%)
+ + \ No newline at end of file diff --git a/bench-results/baseline.json b/bench-results/baseline.json new file mode 100644 index 000000000..07c08a930 --- /dev/null +++ b/bench-results/baseline.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 45.998623277356515, + "samples": [], + "totalTime": 500.00000047683716, + "min": 0, + "max": 106.59999990463257, + "hz": 3337.9999968166353, + "period": 0.2995805874636532, + "mean": 0.2995805874636532, + "variance": 8.250137700731601, + "sd": 2.872305293789572, + "sem": 0.070307625428315, + "df": 1668, + "critical": 1.96, + "moe": 0.13780294583949737, + "p75": 0.19999980926513672, + "p99": 0.40000009536743164, + "p995": 15, + "p999": 23.199999809265137, + "sampleCount": 1669, + "median": 0.10000038146972656 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 24.153991639816926, + "samples": [], + "totalTime": 500.0999984741211, + "min": 0, + "max": 60.299999713897705, + "hz": 3641.2717567609275, + "period": 0.2746293237090176, + "mean": 0.2746293237090176, + "variance": 2.0857845261746553, + "sd": 1.4442245414666846, + "sem": 0.03384384892304177, + "df": 1820, + "critical": 1.96, + "moe": 0.06633394388916188, + "p75": 0.20000028610229492, + "p99": 1, + "p995": 1.0999999046325684, + "p999": 10.599999904632568, + "sampleCount": 1821, + "median": 0.19999980926513672 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 219.71007824396006, + "samples": [], + "totalTime": 580.8999996185303, + "min": 1.5999999046325684, + "max": 565.8999996185303, + "hz": 17.214666907500217, + "period": 58.089999961853025, + "mean": 58.089999961853025, + "variance": 31835.927623604242, + "sd": 178.42625261884598, + "sem": 56.42333526441364, + "df": 9, + "critical": 2.262, + "moe": 127.62958436810365, + "p75": 1.6999998092651367, + "p99": 565.8999996185303, + "p995": 565.8999996185303, + "p999": 565.8999996185303, + "sampleCount": 10, + "median": 1.6999998092651367 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 225.61517409759819, + "samples": [], + "totalTime": 7262.900000095367, + "min": 1.6999998092651367, + "max": 7246, + "hz": 1.3768604827092061, + "period": 726.2900000095367, + "mean": 726.2900000095367, + "variance": 5247730.6854290925, + "sd": 2290.792588915263, + "sem": 724.4122228006022, + "df": 9, + "critical": 2.262, + "moe": 1638.6204479749622, + "p75": 2, + "p99": 7246, + "p995": 7246, + "p999": 7246, + "sampleCount": 10, + "median": 1.9000000953674316 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 9.709491516573806, + "samples": [], + "totalTime": 500.09999656677246, + "min": 0, + "max": 21.90000009536743, + "hz": 13419.316228897353, + "period": 0.07451944517460475, + "mean": 0.07451944517460475, + "variance": 0.09145496646786729, + "sd": 0.3024152219513219, + "sem": 0.003691560820115366, + "df": 6710, + "critical": 1.96, + "moe": 0.007235459207426117, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 0.40000009536743164, + "sampleCount": 6711, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 4.269045223009224, + "samples": [], + "totalTime": 501.8999996185303, + "min": 0, + "max": 4.700000286102295, + "hz": 233.1141663457382, + "period": 4.289743586483165, + "mean": 4.289743586483165, + "variance": 1.0000662823465616, + "sd": 1.0000331406241303, + "sem": 0.09245309655598953, + "df": 116, + "critical": 1.9808, + "moe": 0.18313109365810407, + "p75": 4.599999904632568, + "p99": 4.700000286102295, + "p995": 4.700000286102295, + "p999": 4.700000286102295, + "sampleCount": 117, + "median": 4.5 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 0.33990217845594756, + "samples": [], + "totalTime": 1144.3000001907349, + "min": 113.7999997138977, + "max": 115.2000002861023, + "hz": 8.738967052637573, + "period": 114.43000001907349, + "mean": 114.43000001907349, + "variance": 0.2956667522855039, + "sd": 0.5437524733603553, + "sem": 0.17194962991687532, + "df": 9, + "critical": 2.262, + "moe": 0.388950062871972, + "p75": 114.80000019073486, + "p99": 115.2000002861023, + "p995": 115.2000002861023, + "p999": 115.2000002861023, + "sampleCount": 10, + "median": 114.34999990463257 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 9.345113915984529, + "samples": [], + "totalTime": 500.2999978065491, + "min": 0.19999980926513672, + "max": 18.699999809265137, + "hz": 2792.3246174791666, + "period": 0.3581245510426264, + "mean": 0.3581245510426264, + "variance": 0.40730679243133816, + "sd": 0.638205916951056, + "sem": 0.017075075130633468, + "df": 1396, + "critical": 1.96, + "moe": 0.03346714725604159, + "p75": 0.3000001907348633, + "p99": 1.0999999046325684, + "p995": 1.3000001907348633, + "p999": 10.800000190734863, + "sampleCount": 1397, + "median": 0.3000001907348633 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 4.2488219492828785, + "samples": [], + "totalTime": 502.5999994277954, + "min": 0, + "max": 4.700000286102295, + "hz": 230.79984109045907, + "period": 4.332758615756857, + "mean": 4.332758615756857, + "variance": 1.0008305807213995, + "sd": 1.000415204163451, + "sem": 0.09288621982729822, + "df": 115, + "critical": 1.9819, + "moe": 0.18409119907572236, + "p75": 4.599999904632568, + "p99": 4.700000286102295, + "p995": 4.700000286102295, + "p999": 4.700000286102295, + "sampleCount": 116, + "median": 4.599999904632568 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.9087778114891794, + "samples": [], + "totalTime": 1233.7000002861023, + "min": 120.5, + "max": 132.09999990463257, + "hz": 8.105698304029294, + "period": 123.37000002861024, + "mean": 123.37000002861024, + "variance": 10.83788864072166, + "sd": 3.2920948711605593, + "sem": 1.0410518066225936, + "df": 9, + "critical": 2.262, + "moe": 2.3548591865803066, + "p75": 123.7000002861023, + "p99": 132.09999990463257, + "p995": 132.09999990463257, + "p999": 132.09999990463257, + "sampleCount": 10, + "median": 122.70000004768372 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 6.063449615602265, + "samples": [], + "totalTime": 501.49999618530273, + "min": 1.0999999046325684, + "max": 12.5, + "hz": 636.0917296640027, + "period": 1.5721003015213253, + "mean": 1.5721003015213253, + "variance": 0.7545336079619982, + "sd": 0.8686389399295878, + "sem": 0.048634443719120846, + "df": 318, + "critical": 1.96, + "moe": 0.09532350968947685, + "p75": 1.5999999046325684, + "p99": 3.3999996185302734, + "p995": 8.800000190734863, + "p999": 12.5, + "sampleCount": 319, + "median": 1.4000000953674316 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 3.9859373465017485, + "samples": [], + "totalTime": 501.09999990463257, + "min": 0.19999980926513672, + "max": 5.099999904632568, + "hz": 219.51706250435996, + "period": 4.555454544587569, + "mean": 4.555454544587569, + "variance": 0.9230433809457453, + "sd": 0.9607514667934395, + "sem": 0.09160405811503736, + "df": 109, + "critical": 1.9822, + "moe": 0.18157756399562705, + "p75": 4.800000190734863, + "p99": 5, + "p995": 5.099999904632568, + "p999": 5.099999904632568, + "sampleCount": 110, + "median": 4.799999952316284 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 0.4078431187149724, + "samples": [], + "totalTime": 1235.9000000953674, + "min": 122.60000038146973, + "max": 124.69999980926514, + "hz": 8.09126951956336, + "period": 123.59000000953674, + "mean": 123.59000000953674, + "variance": 0.4965554370880682, + "sd": 0.7046668979653211, + "sem": 0.22283523892958856, + "df": 9, + "critical": 2.262, + "moe": 0.5040533104587294, + "p75": 124, + "p99": 124.69999980926514, + "p995": 124.69999980926514, + "p999": 124.69999980926514, + "sampleCount": 10, + "median": 123.7999997138977 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 6.788488597136699, + "samples": [], + "totalTime": 501.99999952316284, + "min": 8.400000095367432, + "max": 22.100000381469727, + "hz": 93.62549809690063, + "period": 10.680851053684316, + "mean": 10.680851053684316, + "variance": 6.092886501756924, + "sd": 2.4683773013372416, + "sem": 0.36004983407315266, + "df": 46, + "critical": 2.0138, + "moe": 0.7250683558565147, + "p75": 11.199999809265137, + "p99": 22.100000381469727, + "p995": 22.100000381469727, + "p999": 22.100000381469727, + "sampleCount": 47, + "median": 10.099999904632568 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 3.3155418452342102, + "samples": [], + "totalTime": 502, + "min": 1.299999713897705, + "max": 8.100000381469727, + "hz": 211.15537848605578, + "period": 4.735849056603773, + "mean": 4.735849056603773, + "variance": 0.6646073923616815, + "sd": 0.8152345627864912, + "sem": 0.07918258053395243, + "df": 105, + "critical": 1.983, + "moe": 0.15701905719882767, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 8.100000381469727, + "p999": 8.100000381469727, + "sampleCount": 106, + "median": 4.8999998569488525 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 3.790257041812148, + "samples": [], + "totalTime": 1291, + "min": 123.69999980926514, + "max": 148, + "hz": 7.74593338497289, + "period": 129.1, + "mean": 129.1, + "variance": 46.795555807749466, + "sd": 6.840727725012118, + "sem": 2.163228046410028, + "df": 9, + "critical": 2.262, + "moe": 4.893221840979483, + "p75": 128.90000009536743, + "p99": 148, + "p995": 148, + "p999": 148, + "sampleCount": 10, + "median": 127.29999995231628 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 179.80229819312095, + "samples": [], + "totalTime": 690.5999999046326, + "min": 6.099999904632568, + "max": 558.5, + "hz": 14.48016217981601, + "period": 69.05999999046325, + "mean": 69.05999999046325, + "variance": 30134.113777501425, + "sd": 173.59180216099327, + "sem": 54.894547796207796, + "df": 9, + "critical": 2.262, + "moe": 124.17146711502204, + "p75": 6.599999904632568, + "p99": 558.5, + "p995": 558.5, + "p999": 558.5, + "sampleCount": 10, + "median": 6.300000190734863 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 95.8065363729877, + "samples": [], + "totalTime": 710.5, + "min": 36.59999990463257, + "max": 341.69999980926514, + "hz": 14.074595355383533, + "period": 71.05, + "mean": 71.05, + "variance": 9055.93387602912, + "sd": 95.1626706016026, + "sem": 30.093078732541006, + "df": 9, + "critical": 2.262, + "moe": 68.07054409300775, + "p75": 45.5, + "p99": 341.69999980926514, + "p995": 341.69999980926514, + "p999": 341.69999980926514, + "sampleCount": 10, + "median": 41.59999990463257 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 91.17327776809306, + "samples": [], + "totalTime": 2464.199999809265, + "min": 140.2000002861023, + "max": 1140.1999998092651, + "hz": 4.058112166534381, + "period": 246.41999998092652, + "mean": 246.41999998092652, + "variance": 98651.0795181194, + "sd": 314.08769399344413, + "sem": 99.32324980492704, + "df": 9, + "critical": 2.262, + "moe": 224.66919105874499, + "p75": 151.59999990463257, + "p99": 1140.1999998092651, + "p995": 1140.1999998092651, + "p999": 1140.1999998092651, + "sampleCount": 10, + "median": 147.84999990463257 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 125.23849693176088, + "samples": [], + "totalTime": 14219.099999904633, + "min": 597.3000001907349, + "max": 8506.699999809265, + "hz": 0.7032793918086988, + "period": 1421.9099999904633, + "mean": 1421.9099999904633, + "variance": 6197759.3517961325, + "sd": 2489.5299459528765, + "sem": 787.2584932406974, + "df": 9, + "critical": 2.262, + "moe": 1780.7787117104574, + "p75": 669.7000002861023, + "p99": 8506.699999809265, + "p995": 8506.699999809265, + "p999": 8506.699999809265, + "sampleCount": 10, + "median": 634.0999999046326 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 2, + "rme": 35.54420367802527, + "samples": [], + "totalTime": 511.7000002861023, + "min": 4.099999904632568, + "max": 61.40000009536743, + "hz": 50.81102205484238, + "period": 19.680769241773167, + "mean": 19.680769241773167, + "variance": 299.8200163112641, + "sd": 17.315311614616242, + "sem": 3.3958119925718466, + "df": 25, + "critical": 2.06, + "moe": 6.9953727046980045, + "p75": 35.69999980926514, + "p99": 61.40000009536743, + "p995": 61.40000009536743, + "p999": 61.40000009536743, + "sampleCount": 26, + "median": 13.350000143051147 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 1, + "rme": 40.20989908733421, + "samples": [], + "totalTime": 516.8999996185303, + "min": 1.6999998092651367, + "max": 47.39999961853027, + "hz": 56.103695146840515, + "period": 17.824137917880353, + "mean": 17.824137917880353, + "variance": 355.1576122590709, + "sd": 18.845625812348892, + "sem": 3.4995448583823054, + "df": 28, + "critical": 2.048, + "moe": 7.167067869966962, + "p75": 40.80000019073486, + "p99": 47.39999961853027, + "p995": 47.39999961853027, + "p999": 47.39999961853027, + "sampleCount": 29, + "median": 4.299999713897705 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 46.467502512611645, + "samples": [], + "totalTime": 519.5, + "min": 1.6999998092651367, + "max": 58.5, + "hz": 48.12319538017324, + "period": 20.78, + "mean": 20.78, + "variance": 547.1549989366532, + "sd": 23.391344530331153, + "sem": 4.678268906066231, + "df": 24, + "critical": 2.064, + "moe": 9.655947022120701, + "p75": 49.69999980926514, + "p99": 58.5, + "p995": 58.5, + "p999": 58.5, + "sampleCount": 25, + "median": 2.200000286102295 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 2, + "rme": 3.3527352808260935, + "samples": [], + "totalTime": 1062, + "min": 101.5, + "max": 119.40000009536743, + "hz": 9.416195856873824, + "period": 106.2, + "mean": 106.2, + "variance": 24.77777822282583, + "sd": 4.9777282190599585, + "sem": 1.574095874552304, + "df": 9, + "critical": 2.262, + "moe": 3.5606048682373115, + "p75": 105.90000009536743, + "p99": 119.40000009536743, + "p995": 119.40000009536743, + "p999": 119.40000009536743, + "sampleCount": 10, + "median": 105.09999990463257 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 1, + "rme": 15.573097421100671, + "samples": [], + "totalTime": 973, + "min": 57.09999990463257, + "max": 109.30000019073486, + "hz": 10.277492291880781, + "period": 97.3, + "mean": 97.3, + "variance": 448.73555350621547, + "sd": 21.183379180532445, + "sem": 6.69877267494737, + "df": 9, + "critical": 2.262, + "moe": 15.152623790730951, + "p75": 107.40000009536743, + "p99": 109.30000019073486, + "p995": 109.30000019073486, + "p999": 109.30000019073486, + "sampleCount": 10, + "median": 106.84999990463257 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 3, + "rme": 12.696087763298886, + "samples": [], + "totalTime": 1270.2000002861023, + "min": 86.39999961853027, + "max": 154.40000009536743, + "hz": 7.8727759390234455, + "period": 127.02000002861023, + "mean": 127.02000002861023, + "variance": 508.2751153208415, + "sd": 22.544957647350802, + "sem": 7.12934159176597, + "df": 9, + "critical": 2.262, + "moe": 16.126570680574623, + "p75": 140.2000002861023, + "p99": 154.40000009536743, + "p995": 154.40000009536743, + "p999": 154.40000009536743, + "sampleCount": 10, + "median": 135.39999985694885 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 2, + "rme": 2.2790308026131174, + "samples": [], + "totalTime": 6527.599999427795, + "min": 619.9000000953674, + "max": 685.3999996185303, + "hz": 1.5319566151229536, + "period": 652.7599999427796, + "mean": 652.7599999427796, + "variance": 432.5359965892369, + "sd": 20.797499767742202, + "sem": 6.576746890288822, + "df": 9, + "critical": 2.262, + "moe": 14.876601465833316, + "p75": 665.4000000953674, + "p99": 685.3999996185303, + "p995": 685.3999996185303, + "p999": 685.3999996185303, + "sampleCount": 10, + "median": 660.9999997615814 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 2.9328671323017383, + "samples": [], + "totalTime": 7152.400000095367, + "min": 673.5999999046326, + "max": 768, + "hz": 1.3981320955017427, + "period": 715.2400000095367, + "mean": 715.2400000095367, + "variance": 860.0093343645732, + "sd": 29.32591574639355, + "sem": 9.273668822880042, + "df": 9, + "critical": 2.262, + "moe": 20.977038877354655, + "p75": 743.9000000953674, + "p99": 768, + "p995": 768, + "p999": 768, + "sampleCount": 10, + "median": 709.0499999523163 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 1, + "rme": 5.710988540589106, + "samples": [], + "totalTime": 5282.900000095367, + "min": 472.7000002861023, + "max": 626.7999997138977, + "hz": 1.892899733066967, + "period": 528.2900000095367, + "mean": 528.2900000095367, + "variance": 1779.0254309236739, + "sd": 42.178494886893176, + "sem": 13.33801121203485, + "df": 9, + "critical": 2.262, + "moe": 30.17058136162283, + "p75": 543, + "p99": 626.7999997138977, + "p995": 626.7999997138977, + "p999": 626.7999997138977, + "sampleCount": 10, + "median": 528.2999999523163 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 3, + "rme": 12.61282505099486, + "samples": [], + "totalTime": 24914.300000190735, + "min": 1931.1000003814697, + "max": 3206, + "hz": 0.4013759166391769, + "period": 2491.4300000190733, + "mean": 2491.4300000190733, + "variance": 192990.94008209903, + "sd": 439.3073412567778, + "sem": 138.9211791204275, + "df": 9, + "critical": 2.262, + "moe": 314.239707170407, + "p75": 2871.8999996185303, + "p99": 3206, + "p995": 3206, + "p999": 3206, + "sampleCount": 10, + "median": 2405.5499999523163 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 1, + "rme": 12.362126686599744, + "samples": [], + "totalTime": 19523.499999523163, + "min": 1472.9000000953674, + "max": 2340.2000002861023, + "hz": 0.5122032422590334, + "period": 1952.3499999523162, + "mean": 1952.3499999523162, + "variance": 113845.67389027384, + "sd": 337.4102456806459, + "sem": 106.6984882227831, + "df": 9, + "critical": 2.262, + "moe": 241.35198035993537, + "p75": 2282, + "p99": 2340.2000002861023, + "p995": 2340.2000002861023, + "p999": 2340.2000002861023, + "sampleCount": 10, + "median": 1968.9499998092651 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 2, + "rme": 19.340506518466995, + "samples": [], + "totalTime": 19579.099999904633, + "min": 1298, + "max": 2661.2000002861023, + "hz": 0.5107487065313885, + "period": 1957.9099999904633, + "mean": 1957.9099999904633, + "variance": 280243.74992769514, + "sd": 529.3805341412689, + "sem": 167.40482368429386, + "df": 9, + "critical": 2.262, + "moe": 378.6697111738727, + "p75": 2464, + "p99": 2661.2000002861023, + "p995": 2661.2000002861023, + "p999": 2661.2000002861023, + "sampleCount": 10, + "median": 1921.6999998092651 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 3, + "rme": 220.54905840700502, + "samples": [], + "totalTime": 6757.900000095367, + "min": 3.9000000953674316, + "max": 6605.700000286102, + "hz": 1.4797496263423373, + "period": 675.7900000095367, + "mean": 675.7900000095367, + "variance": 4341589.285845477, + "sd": 2083.6480714951545, + "sem": 658.9073748142052, + "df": 9, + "critical": 2.262, + "moe": 1490.4484818297324, + "p75": 40, + "p99": 6605.700000286102, + "p995": 6605.700000286102, + "p999": 6605.700000286102, + "sampleCount": 10, + "median": 5.3999998569488525 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 2, + "rme": 15.243456234373262, + "samples": [], + "totalTime": 827.2000002861023, + "min": 62.5, + "max": 107.2999997138977, + "hz": 12.088974850751107, + "period": 82.72000002861023, + "mean": 82.72000002861023, + "variance": 310.7439965570238, + "sd": 17.627932282517534, + "sem": 5.574441645196618, + "df": 9, + "critical": 2.262, + "moe": 12.60938700143475, + "p75": 96.59999990463257, + "p99": 107.2999997138977, + "p995": 107.2999997138977, + "p999": 107.2999997138977, + "sampleCount": 10, + "median": 84.05000019073486 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 32.55265822289764, + "samples": [], + "totalTime": 504.09999990463257, + "min": 1.1999998092651367, + "max": 30.299999713897705, + "hz": 85.30053562415175, + "period": 11.72325581173564, + "mean": 11.72325581173564, + "variance": 153.68706549772264, + "sd": 12.397058743819949, + "sem": 1.8905337347618583, + "df": 42, + "critical": 2.0186, + "moe": 3.8162313969902875, + "p75": 28.600000381469727, + "p99": 30.299999713897705, + "p995": 30.299999713897705, + "p999": 30.299999713897705, + "sampleCount": 43, + "median": 2.299999713897705 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 5.073263279138366, + "samples": [], + "totalTime": 754, + "min": 68.89999961853027, + "max": 87.59999990463257, + "hz": 13.26259946949602, + "period": 75.4, + "mean": 75.4, + "variance": 28.597778110504187, + "sd": 5.347689043923944, + "sem": 1.6910877597127887, + "df": 9, + "critical": 2.262, + "moe": 3.825240512470328, + "p75": 76.5, + "p99": 87.59999990463257, + "p995": 87.59999990463257, + "p999": 87.59999990463257, + "sampleCount": 10, + "median": 74.04999995231628 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 1.9812790322692369, + "samples": [], + "totalTime": 6296.800000190735, + "min": 607.8000001907349, + "max": 661.2000002861023, + "hz": 1.5881082454099054, + "period": 629.6800000190735, + "mean": 629.6800000190735, + "variance": 304.1906665657892, + "sd": 17.44106265586444, + "sem": 5.5153482806237095, + "df": 9, + "critical": 2.262, + "moe": 12.475717810770831, + "p75": 640.0999999046326, + "p99": 661.2000002861023, + "p995": 661.2000002861023, + "p999": 661.2000002861023, + "sampleCount": 10, + "median": 625.7999999523163 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 15.559165607675135, + "samples": [], + "totalTime": 898, + "min": 52.799999713897705, + "max": 102.40000009536743, + "hz": 11.1358574610245, + "period": 89.8, + "mean": 89.8, + "variance": 381.5400030496386, + "sd": 19.53304899521932, + "sem": 6.176892447255646, + "df": 9, + "critical": 2.262, + "moe": 13.972130715692272, + "p75": 100.19999980926514, + "p99": 102.40000009536743, + "p995": 102.40000009536743, + "p999": 102.40000009536743, + "sampleCount": 10, + "median": 97.84999990463257 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 2, + "rme": 4.667020346417675, + "samples": [], + "totalTime": 4902.400000095367, + "min": 445.2999997138977, + "max": 550.6000003814697, + "hz": 2.039817232336298, + "period": 490.24000000953674, + "mean": 490.24000000953674, + "variance": 1023.0848993551467, + "sd": 31.98569835653345, + "sem": 10.114765935775017, + "df": 9, + "critical": 2.262, + "moe": 22.87960054672309, + "p75": 499.90000009536743, + "p99": 550.6000003814697, + "p995": 550.6000003814697, + "p999": 550.6000003814697, + "sampleCount": 10, + "median": 489.2999997138977 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 24.761863395777535, + "samples": [], + "totalTime": 21787.900000095367, + "min": 1541.5, + "max": 4193.799999713898, + "hz": 0.45897034592394076, + "period": 2178.790000009537, + "mean": 2178.790000009537, + "variance": 568868.9008644343, + "sd": 754.2339828358533, + "sem": 238.50972744616396, + "df": 9, + "critical": 2.262, + "moe": 539.5090034832228, + "p75": 2290.4000000953674, + "p99": 4193.799999713898, + "p995": 4193.799999713898, + "p999": 4193.799999713898, + "sampleCount": 10, + "median": 2012.3999998569489 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 1, + "rme": 8.22410736622983, + "samples": [], + "totalTime": 4092.3999996185303, + "min": 352.5, + "max": 482.7999997138977, + "hz": 2.443553905026914, + "period": 409.239999961853, + "mean": 409.239999961853, + "variance": 2213.851538380093, + "sd": 47.051583803099476, + "sem": 14.879017233608181, + "df": 9, + "critical": 2.262, + "moe": 33.656336982421706, + "p75": 467.7999997138977, + "p99": 482.7999997138977, + "p995": 482.7999997138977, + "p999": 482.7999997138977, + "sampleCount": 10, + "median": 384.65000009536743 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 2, + "rme": 3.72622694774277, + "samples": [], + "totalTime": 60233.2000002861, + "min": 5480.900000095367, + "max": 6562.5, + "hz": 0.16602139683683584, + "period": 6023.320000028611, + "mean": 6023.320000028611, + "variance": 98452.16624471496, + "sd": 313.7708817667996, + "sem": 99.22306498224842, + "df": 9, + "critical": 2.262, + "moe": 224.44257298984593, + "p75": 6199.099999904633, + "p99": 6562.5, + "p995": 6562.5, + "p999": 6562.5, + "sampleCount": 10, + "median": 5963.700000047684 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 6.06885637570229, + "samples": [], + "totalTime": 109387.19999980927, + "min": 9029.5, + "max": 12545.400000095367, + "hz": 0.09141837436205914, + "period": 10938.719999980927, + "mean": 10938.719999980927, + "variance": 861314.046312269, + "sd": 928.0700654111569, + "sem": 293.4815234920708, + "df": 9, + "critical": 2.262, + "moe": 663.8552061390641, + "p75": 11621.5, + "p99": 12545.400000095367, + "p995": 12545.400000095367, + "p999": 12545.400000095367, + "sampleCount": 10, + "median": 10856.649999856949 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 1, + "rme": 17.239999051688244, + "samples": [], + "totalTime": 22587.699999809265, + "min": 828.5999999046326, + "max": 2745.0999999046326, + "hz": 0.4427188248508897, + "period": 2258.7699999809265, + "mean": 2258.7699999809265, + "variance": 296369.3556949535, + "sd": 544.3981591583072, + "sem": 172.15381369431046, + "df": 9, + "critical": 2.262, + "moe": 389.4119265765303, + "p75": 2518.7999997138977, + "p99": 2745.0999999046326, + "p995": 2745.0999999046326, + "p999": 2745.0999999046326, + "sampleCount": 10, + "median": 2369.800000190735 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/comparison.html b/bench-results/comparison.html new file mode 100644 index 000000000..44f339c68 --- /dev/null +++ b/bench-results/comparison.html @@ -0,0 +1,101 @@ + + + + +Onyx Benchmark Results + + + +

Onyx Benchmark Results

+

Generated 2/11/2026, 9:48:46 AM

+
+All values are mean time in milliseconds (lower is better). +Green = faster (improvement, ≥5% and ≥1ms) +Red = slower (regression, ≥5% and ≥1ms) +Gray = negligible +⚠ = unreliable (high variance, few samples) +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationBaseline (main)Current (WriteBuffer+Worker)
Onyx.set()
Small (50 reports, 50 txns)6764.99 (-99%)
Modest (250 reports, 250 txns)75.44.76 (-94%)
Heavy (1000 reports, 1000 txns)4905.94 (-99%)
Extreme (5000 reports, 5000 txns)602333.1 (-99%)
Onyx.multiSet()
Small (50 reports, 50 txns)82.76.49 (-92%)
Modest (250 reports, 250 txns)63014.9 (-98%)
Heavy (1000 reports, 1000 txns)217953.8 (-98%)
Extreme (5000 reports, 5000 txns)10939211 (-98%)
Onyx.setCollection()
Small (50 reports, 50 txns)11.74.74 (-60%)
Modest (250 reports, 250 txns)89.85.86 (-93%)
Heavy (1000 reports, 1000 txns)4098.74 (-98%)
Extreme (5000 reports, 5000 txns)225951.3 (-98%)
Onyx.merge()
Small (50 reports, 50 txns)19.74.75 (-76%)
Modest (250 reports, 250 txns)1064.59 (-96%)
Heavy (1000 reports, 1000 txns)6535.67 (-99%)
Extreme (5000 reports, 5000 txns)249127.4 (-99%)
Onyx.mergeCollection()
Small (50 reports, 50 txns)17.84.79 (-73%)
Modest (250 reports, 250 txns)97.36.04 (-94%)
Heavy (1000 reports, 1000 txns)71511.2 (-98%)
Extreme (5000 reports, 5000 txns)195232.3 (-98%)
Onyx.update()
Small (50 reports, 50 txns)20.84.88 (-76%)
Modest (250 reports, 250 txns)1275.79 (-95%)
Heavy (1000 reports, 1000 txns)5289.36 (-98%)
Extreme (5000 reports, 5000 txns)195843.2 (-98%)
Onyx.connect() - register subscribers
Small (50 reports, 50 txns)0.0750.063 (-15%)
Modest (250 reports, 250 txns)0.3580.541 (+51%)
Heavy (1000 reports, 1000 txns)1.571.45 (-8%)
Extreme (5000 reports, 5000 txns)10.78.64 (-19%)
Onyx.connect() - collection subscriber
Small (50 reports, 50 txns)4.294.64 (+8%)
Modest (250 reports, 250 txns)4.334.60 (+6%)
Heavy (1000 reports, 1000 txns)4.564.82 (+6%)
Extreme (5000 reports, 5000 txns)4.744.60 (-3%)
Notification throughput
Small (50 reports, 50 txns)114117 (+2%)
Modest (250 reports, 250 txns)123118 (-4%)
Heavy (1000 reports, 1000 txns)124117 (-6%)
Extreme (5000 reports, 5000 txns)129117 (-10%)
Onyx.init()
Small (50 reports, 50 txns)69.13.88 (-94%)
Modest (250 reports, 250 txns)71.023.6 (-67%)
Heavy (1000 reports, 1000 txns)24697.3 (-61%)
Extreme (5000 reports, 5000 txns)1422426 (-70%)
Onyx.clear()
Small (50 reports, 50 txns)0.3000.189 (-37%)
Modest (250 reports, 250 txns)0.2750.182 (-34%)
Heavy (1000 reports, 1000 txns)58.10.288 (-100%)
Extreme (5000 reports, 5000 txns)72654.9 (-92%)
+ + \ No newline at end of file diff --git a/bench-results/current.json b/bench-results/current.json new file mode 100644 index 000000000..463834f1f --- /dev/null +++ b/bench-results/current.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 17.456231187803226, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 43.59999990463257, + "hz": 5298.940218020552, + "period": 0.18871698091614922, + "mean": 0.18871698091614922, + "variance": 0.7486117880721845, + "sd": 0.8652235480337925, + "sem": 0.016807587999676278, + "df": 2649, + "critical": 1.96, + "moe": 0.032942872479365504, + "p75": 0.20000028610229492, + "p99": 0.3000001907348633, + "p995": 0.3000001907348633, + "p999": 5.299999713897705, + "sampleCount": 2650, + "median": 0.19999980926513672 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 10.372419784400732, + "samples": [], + "totalTime": 500.1000003814697, + "min": 0, + "max": 24.40000009536743, + "hz": 5502.899415918438, + "period": 0.18172238385954567, + "mean": 0.18172238385954567, + "variance": 0.25451495569099997, + "sd": 0.5044947528874805, + "sem": 0.009616841069455182, + "df": 2751, + "critical": 1.96, + "moe": 0.018849008496132157, + "p75": 0.20000028610229492, + "p99": 0.3000001907348633, + "p995": 0.3000001907348633, + "p999": 1.8000001907348633, + "sampleCount": 2752, + "median": 0.19999980926513672 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 36.26383812935296, + "samples": [], + "totalTime": 500.19999980926514, + "min": 0, + "max": 91.90000009536743, + "hz": 3470.611756621285, + "period": 0.28813364044312506, + "mean": 0.28813364044312506, + "variance": 4.933703496461936, + "sd": 2.2211941600098664, + "sem": 0.053310365799238146, + "df": 1735, + "critical": 1.96, + "moe": 0.10448831696650676, + "p75": 0.20000028610229492, + "p99": 1.5999999046325684, + "p995": 2.4000000953674316, + "p999": 5.399999618530273, + "sampleCount": 1736, + "median": 0.19999980926513672 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 224.69070531292655, + "samples": [], + "totalTime": 549.3999996185303, + "min": 0.09999990463256836, + "max": 546.0999999046326, + "hz": 18.201674566697104, + "period": 54.939999961853026, + "mean": 54.939999961853026, + "variance": 29782.580437475415, + "sd": 172.5763032327307, + "sem": 54.57341883873084, + "df": 9, + "critical": 2.262, + "moe": 123.44507341320916, + "p75": 0.40000009536743164, + "p99": 546.0999999046326, + "p995": 546.0999999046326, + "p999": 546.0999999046326, + "sampleCount": 10, + "median": 0.2999999523162842 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 10.588809590487292, + "samples": [], + "totalTime": 500.00000047683716, + "min": 0, + "max": 24, + "hz": 15817.999984914779, + "period": 0.0632191175214107, + "mean": 0.0632191175214107, + "variance": 0.09225726356775235, + "sd": 0.30373880813579346, + "sem": 0.003415383662820698, + "df": 7908, + "critical": 1.96, + "moe": 0.006694151979128569, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 0.40000009536743164, + "sampleCount": 7909, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 0.6556035965589754, + "samples": [], + "totalTime": 501.30000019073486, + "min": 4.300000190734863, + "max": 5.400000095367432, + "hz": 215.43985629145843, + "period": 4.64166666843273, + "mean": 4.64166666843273, + "variance": 0.025443924906868958, + "sd": 0.1595115196682326, + "sem": 0.015349003136550063, + "df": 107, + "critical": 1.9826, + "moe": 0.030430933618524152, + "p75": 4.699999809265137, + "p99": 5.199999809265137, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 108, + "median": 4.599999904632568 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 2.2652619568215826, + "samples": [], + "totalTime": 1172.3999996185303, + "min": 112.59999990463257, + "max": 122.69999980926514, + "hz": 8.52951211468249, + "period": 117.23999996185303, + "mean": 117.23999996185303, + "variance": 13.784889239841059, + "sd": 3.7128007271924868, + "sem": 1.1740906796257713, + "df": 9, + "critical": 2.262, + "moe": 2.6557931173134945, + "p75": 120.80000019073486, + "p99": 122.69999980926514, + "p995": 122.69999980926514, + "p999": 122.69999980926514, + "sampleCount": 10, + "median": 116.64999985694885 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 19.515022112669655, + "samples": [], + "totalTime": 500.00000762939453, + "min": 0.19999980926513672, + "max": 50.09999990463257, + "hz": 1849.9999717712406, + "period": 0.5405405487885346, + "mean": 0.5405405487885346, + "variance": 2.679317877687371, + "sd": 1.6368622048564048, + "sem": 0.053819697767361445, + "df": 924, + "critical": 1.96, + "moe": 0.10548660762402844, + "p75": 0.5, + "p99": 1.0999999046325684, + "p995": 1.200000286102295, + "p999": 50.09999990463257, + "sampleCount": 925, + "median": 0.5 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 0.724297200237698, + "samples": [], + "totalTime": 501.7000002861023, + "min": 4.099999904632568, + "max": 5.5, + "hz": 217.26131141686474, + "period": 4.602752296202773, + "mean": 4.602752296202773, + "variance": 0.030825685233144648, + "sd": 0.17557245009723094, + "sem": 0.01681679076638067, + "df": 108, + "critical": 1.9824, + "moe": 0.03333760601527304, + "p75": 4.699999809265137, + "p99": 5.099999904632568, + "p995": 5.5, + "p999": 5.5, + "sampleCount": 109, + "median": 4.599999904632568 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 0.8580136689276511, + "samples": [], + "totalTime": 1182.4000000953674, + "min": 115.59999990463257, + "max": 119.90000009536743, + "hz": 8.457374830170368, + "period": 118.24000000953674, + "mean": 118.24000000953674, + "variance": 2.0115556606717115, + "sd": 1.4182932209778454, + "sem": 0.4485036968266495, + "df": 9, + "critical": 2.262, + "moe": 1.0145153622218812, + "p75": 119.2000002861023, + "p99": 119.90000009536743, + "p995": 119.90000009536743, + "p999": 119.90000009536743, + "sampleCount": 10, + "median": 118.84999990463257 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 6.345361735329096, + "samples": [], + "totalTime": 500.3999972343445, + "min": 1, + "max": 12, + "hz": 689.4484450575078, + "period": 1.4504347745923027, + "mean": 1.4504347745923027, + "variance": 0.760704753529602, + "sd": 0.8721838989167376, + "sem": 0.04695680264433, + "df": 344, + "critical": 1.96, + "moe": 0.0920353331828868, + "p75": 1.4000000953674316, + "p99": 5.099999904632568, + "p995": 11, + "p999": 12, + "sampleCount": 345, + "median": 1.299999713897705 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 4.178070878394658, + "samples": [], + "totalTime": 501, + "min": 4.299999713897705, + "max": 15.199999809265137, + "hz": 207.58483033932134, + "period": 4.8173076923076925, + "mean": 4.8173076923076925, + "variance": 1.0709596319533838, + "sd": 1.034871794935674, + "sem": 0.10147752839314987, + "df": 103, + "critical": 1.9834, + "moe": 0.20127052981497345, + "p75": 4.799999713897705, + "p99": 5.299999713897705, + "p995": 15.199999809265137, + "p999": 15.199999809265137, + "sampleCount": 104, + "median": 4.700000286102295 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 2.141245098259286, + "samples": [], + "totalTime": 1166.2999997138977, + "min": 113.39999961853027, + "max": 123, + "hz": 8.574123297996293, + "period": 116.62999997138976, + "mean": 116.62999997138976, + "variance": 12.189001021279287, + "sd": 3.491274985056217, + "sem": 1.1040380890747965, + "df": 9, + "critical": 2.262, + "moe": 2.49733415748719, + "p75": 118.5, + "p99": 123, + "p995": 123, + "p999": 123, + "sampleCount": 10, + "median": 114.59999990463257 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 5.909792038616995, + "samples": [], + "totalTime": 501.39999866485596, + "min": 6.799999713897705, + "max": 19.5, + "hz": 115.67610720870417, + "period": 8.644827563187171, + "mean": 8.644827563187171, + "variance": 3.7744464222561573, + "sd": 1.9427934584654534, + "sem": 0.2551012788143022, + "df": 57, + "critical": 2.0027, + "moe": 0.510891331081403, + "p75": 9.199999809265137, + "p99": 19.5, + "p995": 19.5, + "p999": 19.5, + "sampleCount": 58, + "median": 8.049999952316284 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 0.6526648561103462, + "samples": [], + "totalTime": 501.40000009536743, + "min": 4.099999904632568, + "max": 5, + "hz": 217.39130430647774, + "period": 4.600000000874931, + "mean": 4.600000000874931, + "variance": 0.025000001766097162, + "sd": 0.15811388859330847, + "sem": 0.015144563855319962, + "df": 108, + "critical": 1.9824, + "moe": 0.030022583386786292, + "p75": 4.699999809265137, + "p99": 5, + "p995": 5, + "p999": 5, + "sampleCount": 109, + "median": 4.599999904632568 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 2.1888615527314017, + "samples": [], + "totalTime": 1165.8000001907349, + "min": 113.30000019073486, + "max": 123.69999980926514, + "hz": 8.577800650509449, + "period": 116.58000001907348, + "mean": 116.58000001907348, + "variance": 12.726221763187006, + "sd": 3.567383041276477, + "sem": 1.1281055696692133, + "df": 9, + "critical": 2.262, + "moe": 2.5517747985917603, + "p75": 118.59999990463257, + "p99": 123.69999980926514, + "p995": 123.69999980926514, + "p999": 123.69999980926514, + "sampleCount": 10, + "median": 116.04999995231628 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 8.935358521812814, + "samples": [], + "totalTime": 501, + "min": 3.200000286102295, + "max": 24.5, + "hz": 257.4850299401198, + "period": 3.883720930232558, + "mean": 3.883720930232558, + "variance": 4.043873525501016, + "sd": 2.010938468850058, + "sem": 0.17705325974640956, + "df": 128, + "critical": 1.96, + "moe": 0.34702438910296274, + "p75": 3.5999999046325684, + "p99": 10.799999713897705, + "p995": 24.5, + "p999": 24.5, + "sampleCount": 129, + "median": 3.5 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 15.251092432042734, + "samples": [], + "totalTime": 518.5999999046326, + "min": 20, + "max": 59.40000009536743, + "hz": 42.42190513699512, + "period": 23.572727268392388, + "mean": 23.572727268392388, + "variance": 65.72303046263661, + "sd": 8.106974186627006, + "sem": 1.7284127040653199, + "df": 21, + "critical": 2.08, + "moe": 3.5950984244558657, + "p75": 22.299999713897705, + "p99": 59.40000009536743, + "p995": 59.40000009536743, + "p999": 59.40000009536743, + "sampleCount": 22, + "median": 21.649999856948853 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 23.740598656474248, + "samples": [], + "totalTime": 973.3000001907349, + "min": 84.59999990463257, + "max": 188.60000038146973, + "hz": 10.274324461153117, + "period": 97.33000001907348, + "mean": 97.33000001907348, + "variance": 1043.4978968497383, + "sd": 32.30321805718028, + "sem": 10.215174481376899, + "df": 9, + "critical": 2.262, + "moe": 23.106724676874546, + "p75": 89, + "p99": 188.60000038146973, + "p995": 188.60000038146973, + "p999": 188.60000038146973, + "sampleCount": 10, + "median": 85.84999990463257 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 22.489108420221196, + "samples": [], + "totalTime": 4261.799999713898, + "min": 367.5, + "max": 804.8999996185303, + "hz": 2.346426392761584, + "period": 426.17999997138975, + "mean": 426.17999997138975, + "variance": 17953.346185593502, + "sd": 133.99009734153304, + "sem": 42.37138915069165, + "df": 9, + "critical": 2.262, + "moe": 95.8440822588645, + "p75": 404, + "p99": 804.8999996185303, + "p995": 804.8999996185303, + "p999": 804.8999996185303, + "sampleCount": 10, + "median": 381.55000019073486 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.3268909595791289, + "samples": [], + "totalTime": 503.90000009536743, + "min": 4.5, + "max": 4.900000095367432, + "hz": 210.35919821380944, + "period": 4.753773585805353, + "mean": 4.753773585805353, + "variance": 0.006509434227938937, + "sd": 0.0806810648661688, + "sem": 0.007836437766443913, + "df": 105, + "critical": 1.983, + "moe": 0.015539656090858282, + "p75": 4.800000190734863, + "p99": 4.900000095367432, + "p995": 4.900000095367432, + "p999": 4.900000095367432, + "sampleCount": 106, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.3908067800138435, + "samples": [], + "totalTime": 503.2000002861023, + "min": 4.5, + "max": 4.900000095367432, + "hz": 208.6645467812015, + "period": 4.792380955105736, + "mean": 4.792380955105736, + "variance": 0.009364468172840638, + "sd": 0.09677018225073589, + "sem": 0.009443802791773601, + "df": 104, + "critical": 1.9832, + "moe": 0.018728949696645406, + "p75": 4.899999618530273, + "p99": 4.900000095367432, + "p995": 4.900000095367432, + "p999": 4.900000095367432, + "sampleCount": 105, + "median": 4.800000190734863 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 0.4121986899659845, + "samples": [], + "totalTime": 503, + "min": 4.599999904632568, + "max": 5.400000095367432, + "hz": 204.7713717693837, + "period": 4.883495145631068, + "mean": 4.883495145631068, + "variance": 0.010607273344026943, + "sd": 0.10299161783381666, + "sem": 0.010148065645716731, + "df": 102, + "critical": 1.9836, + "moe": 0.02012970301484371, + "p75": 4.900000095367432, + "p99": 5.099999904632568, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 103, + "median": 4.900000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 0.6529967759099219, + "samples": [], + "totalTime": 500.59999990463257, + "min": 4.399999618530273, + "max": 5.700000286102295, + "hz": 217.73871358522808, + "period": 4.592660549583785, + "mean": 4.592660549583785, + "variance": 0.024945642171273593, + "sd": 0.15794189492111835, + "sem": 0.015128089849308421, + "df": 108, + "critical": 1.9824, + "moe": 0.029989925317269014, + "p75": 4.600000381469727, + "p99": 5.099999904632568, + "p995": 5.700000286102295, + "p999": 5.700000286102295, + "sampleCount": 109, + "median": 4.599999904632568 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 3, + "rme": 0.5443425605914529, + "samples": [], + "totalTime": 501.2999997138977, + "min": 5.5, + "max": 6.5, + "hz": 165.56951934444407, + "period": 6.039759032697563, + "mean": 6.039759032697563, + "variance": 0.022668233258306733, + "sd": 0.15055973319020838, + "sem": 0.016526077697868444, + "df": 82, + "critical": 1.9894, + "moe": 0.03287697897213948, + "p75": 6.099999904632568, + "p99": 6.5, + "p995": 6.5, + "p999": 6.5, + "sampleCount": 83, + "median": 6 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 2, + "rme": 1.944040118375296, + "samples": [], + "totalTime": 503.59999990463257, + "min": 5.099999904632568, + "max": 6.599999904632568, + "hz": 172.75615571182547, + "period": 5.78850574603026, + "mean": 5.78850574603026, + "variance": 0.27870354785478824, + "sd": 0.5279238087591696, + "sem": 0.05659937328100165, + "df": 86, + "critical": 1.9882, + "moe": 0.11253087395728747, + "p75": 6.400000095367432, + "p99": 6.599999904632568, + "p995": 6.599999904632568, + "p999": 6.599999904632568, + "sampleCount": 87, + "median": 5.5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 1.1761725754646075, + "samples": [], + "totalTime": 504.2000002861023, + "min": 5.099999904632568, + "max": 6.599999904632568, + "hz": 176.51725495735425, + "period": 5.665168542540475, + "mean": 5.665168542540475, + "variance": 0.10002298199488956, + "sd": 0.316264101653807, + "sem": 0.03352392772751513, + "df": 88, + "critical": 1.9876, + "moe": 0.06663215875120908, + "p75": 5.899999618530273, + "p99": 6.599999904632568, + "p995": 6.599999904632568, + "p999": 6.599999904632568, + "sampleCount": 89, + "median": 5.599999904632568 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 3.987581235384145, + "samples": [], + "totalTime": 504.2999997138977, + "min": 10.5, + "max": 20.699999809265137, + "hz": 89.23259969369354, + "period": 11.206666660308837, + "mean": 11.206666660308837, + "variance": 2.210636256218006, + "sd": 1.4868208554556954, + "sem": 0.22164216687755492, + "df": 44, + "critical": 2.0162, + "moe": 0.44687493685852625, + "p75": 11.299999713897705, + "p99": 20.699999809265137, + "p995": 20.699999809265137, + "p999": 20.699999809265137, + "sampleCount": 45, + "median": 10.900000095367432 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 1.1759661044400858, + "samples": [], + "totalTime": 505.7000002861023, + "min": 8.599999904632568, + "max": 10.599999904632568, + "hz": 106.78267741635204, + "period": 9.364814820113006, + "mean": 9.364814820113006, + "variance": 0.1627009203516111, + "sd": 0.4033620214541908, + "sem": 0.05489061856557381, + "df": 53, + "critical": 2.0063, + "moe": 0.11012704802811074, + "p75": 9.5, + "p99": 10.599999904632568, + "p995": 10.599999904632568, + "p999": 10.599999904632568, + "sampleCount": 54, + "median": 9.300000190734863 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 1.9691983456155189, + "samples": [], + "totalTime": 519.7999997138977, + "min": 25.800000190734863, + "max": 30.200000286102295, + "hz": 36.55252022019577, + "period": 27.35789472178409, + "mean": 27.35789472178409, + "variance": 1.249239674674179, + "sd": 1.1176939092051004, + "sem": 0.2564165684229451, + "df": 18, + "critical": 2.101, + "moe": 0.5387312102566076, + "p75": 28.199999809265137, + "p99": 30.200000286102295, + "p995": 30.200000286102295, + "p999": 30.200000286102295, + "sampleCount": 19, + "median": 27.299999713897705 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 1.857265786667002, + "samples": [], + "totalTime": 516.4000000953674, + "min": 30.59999990463257, + "max": 34.39999961853027, + "hz": 30.98373353416956, + "period": 32.275000005960464, + "mean": 32.275000005960464, + "variance": 1.2659999901454042, + "sd": 1.1251666499436446, + "sem": 0.28129166248591114, + "df": 15, + "critical": 2.131, + "moe": 0.5994325327574765, + "p75": 32.40000009536743, + "p99": 34.39999961853027, + "p995": 34.39999961853027, + "p999": 34.39999961853027, + "sampleCount": 16, + "median": 32.10000014305115 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 1.811794572014827, + "samples": [], + "totalTime": 518, + "min": 41, + "max": 45.200000286102295, + "hz": 23.166023166023166, + "period": 43.166666666666664, + "mean": 43.166666666666664, + "variance": 1.5151516278585377, + "sd": 1.2309149555751355, + "sem": 0.3553345404754204, + "df": 11, + "critical": 2.201, + "moe": 0.7820913235864003, + "p75": 43.69999980926514, + "p99": 45.200000286102295, + "p995": 45.200000286102295, + "p999": 45.200000286102295, + "sampleCount": 12, + "median": 43.200000047683716 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 2.077971203067055, + "samples": [], + "totalTime": 503.90000009536743, + "min": 0.40000009536743164, + "max": 5.5, + "hz": 200.43659452447883, + "period": 4.989108911835321, + "mean": 4.989108911835321, + "variance": 0.2757801839262307, + "sd": 0.525147773418331, + "sem": 0.05225415649072081, + "df": 100, + "critical": 1.984, + "moe": 0.10367224647759007, + "p75": 5.199999809265137, + "p99": 5.5, + "p995": 5.5, + "p999": 5.5, + "sampleCount": 101, + "median": 5 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.0582760448615491, + "samples": [], + "totalTime": 505.90000009536743, + "min": 5.799999713897705, + "max": 7.199999809265137, + "hz": 154.18066808716384, + "period": 6.485897437120095, + "mean": 6.485897437120095, + "variance": 0.09265568388332895, + "sd": 0.3043939616407148, + "sem": 0.03446582920980724, + "df": 77, + "critical": 1.9915, + "moe": 0.06863869887133112, + "p75": 6.699999809265137, + "p99": 7.199999809265137, + "p995": 7.199999809265137, + "p999": 7.199999809265137, + "sampleCount": 78, + "median": 6.5 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.538258398059661, + "samples": [], + "totalTime": 502.59999990463257, + "min": 0.19999980926513672, + "max": 5.5, + "hz": 210.9033028653269, + "period": 4.741509433062571, + "mean": 4.741509433062571, + "variance": 1.248165328660779, + "sd": 1.1172131974966903, + "sem": 0.10851333839674894, + "df": 105, + "critical": 1.983, + "moe": 0.21518195004075316, + "p75": 5.199999809265137, + "p99": 5.399999618530273, + "p995": 5.5, + "p999": 5.5, + "sampleCount": 106, + "median": 5 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.002872239233372, + "samples": [], + "totalTime": 500.2999997138977, + "min": 4.099999904632568, + "max": 5.400000095367432, + "hz": 209.8740756746861, + "period": 4.764761902037121, + "mean": 4.764761902037121, + "variance": 0.0609578860845719, + "sd": 0.2468965088545642, + "sem": 0.02409463210019074, + "df": 104, + "critical": 1.9832, + "moe": 0.04778447438109828, + "p75": 4.900000095367432, + "p99": 5.300000190734863, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 105, + "median": 4.799999713897705 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 3.343019339298512, + "samples": [], + "totalTime": 506.49999952316284, + "min": 13, + "max": 19.800000190734863, + "hz": 67.12734458442016, + "period": 14.89705880950479, + "mean": 14.89705880950479, + "variance": 2.034839718915612, + "sd": 1.426478082171476, + "sem": 0.24463897282920757, + "df": 33, + "critical": 2.0357, + "moe": 0.4980115569884178, + "p75": 15, + "p99": 19.800000190734863, + "p995": 19.800000190734863, + "p999": 19.800000190734863, + "sampleCount": 34, + "median": 14.550000190734863 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 18.126778799116792, + "samples": [], + "totalTime": 503.90000009536743, + "min": 0.9000000953674316, + "max": 50.09999990463257, + "hz": 170.66878345648692, + "period": 5.859302326690319, + "mean": 5.859302326690319, + "variance": 24.534677018018204, + "sd": 4.953249137487252, + "sem": 0.5341225908627898, + "df": 85, + "critical": 1.9885, + "moe": 1.0621027719306575, + "p75": 5.699999809265137, + "p99": 50.09999990463257, + "p995": 50.09999990463257, + "p999": 50.09999990463257, + "sampleCount": 86, + "median": 5.599999904632568 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 2.3164662741914777, + "samples": [], + "totalTime": 504.59999990463257, + "min": 5.099999904632568, + "max": 8.699999809265137, + "hz": 168.45025766164224, + "period": 5.936470587113324, + "mean": 5.936470587113324, + "variance": 0.4063921469547174, + "sd": 0.6374889386920509, + "sem": 0.06914538366239792, + "df": 84, + "critical": 1.9888, + "moe": 0.13751633902777696, + "p75": 6, + "p99": 8.699999809265137, + "p995": 8.699999809265137, + "p999": 8.699999809265137, + "sampleCount": 85, + "median": 5.700000286102295 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 9.152042836899184, + "samples": [], + "totalTime": 538, + "min": 50.09999990463257, + "max": 72.7000002861023, + "hz": 18.58736059479554, + "period": 53.8, + "mean": 53.8, + "variance": 47.382223676045776, + "sd": 6.883474680424544, + "sem": 2.1767458206241206, + "df": 9, + "critical": 2.262, + "moe": 4.9237990462517605, + "p75": 52, + "p99": 72.7000002861023, + "p995": 72.7000002861023, + "p999": 72.7000002861023, + "sampleCount": 10, + "median": 51.50000023841858 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 4.4244040337851995, + "samples": [], + "totalTime": 507.09999990463257, + "min": 4.099999904632568, + "max": 12.700000286102295, + "hz": 114.37586277047473, + "period": 8.743103446631595, + "mean": 8.743103446631595, + "variance": 2.1638990235776143, + "sd": 1.4710197223618773, + "sem": 0.19315435240963755, + "df": 57, + "critical": 2.0027, + "moe": 0.3868302215707811, + "p75": 9.399999618530273, + "p99": 12.700000286102295, + "p995": 12.700000286102295, + "p999": 12.700000286102295, + "sampleCount": 58, + "median": 9.099999904632568 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 6.6434468775413995, + "samples": [], + "totalTime": 529.0999999046326, + "min": 29.699999809265137, + "max": 42.90000009536743, + "hz": 30.240030245480842, + "period": 33.068749994039536, + "mean": 33.068749994039536, + "variance": 17.00495841050152, + "sd": 4.123706877373987, + "sem": 1.0309267193434968, + "df": 15, + "critical": 2.131, + "moe": 2.1969048389209913, + "p75": 32.19999980926514, + "p99": 42.90000009536743, + "p995": 42.90000009536743, + "p999": 42.90000009536743, + "sampleCount": 16, + "median": 31.75 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 3.7419435434845716, + "samples": [], + "totalTime": 2112, + "min": 200.09999990463257, + "max": 238.40000009536743, + "hz": 4.734848484848485, + "period": 211.2, + "mean": 211.2, + "variance": 122.06666748258807, + "sd": 11.048378500150513, + "sem": 3.493804051211059, + "df": 9, + "critical": 2.262, + "moe": 7.902984763839415, + "p75": 214.59999990463257, + "p99": 238.40000009536743, + "p995": 238.40000009536743, + "p999": 238.40000009536743, + "sampleCount": 10, + "median": 208.45000004768372 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 58.020450019259876, + "samples": [], + "totalTime": 513.0999999046326, + "min": 33.69999980926514, + "max": 168.90000009536743, + "hz": 19.489378292454983, + "period": 51.309999990463254, + "mean": 51.309999990463254, + "variance": 1732.1321149429746, + "sd": 41.618891322847304, + "sem": 13.161049027121564, + "df": 9, + "critical": 2.262, + "moe": 29.770292899348977, + "p75": 43.80000019073486, + "p99": 168.90000009536743, + "p995": 168.90000009536743, + "p999": 168.90000009536743, + "sampleCount": 10, + "median": 37.09999990463257 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/dm-idb-new.json b/bench-results/dm-idb-new.json new file mode 100644 index 000000000..88af91d9e --- /dev/null +++ b/bench-results/dm-idb-new.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 6.21292184765606, + "samples": [], + "totalTime": 500, + "min": 0, + "max": 10, + "hz": 9274, + "period": 0.10782833728703903, + "mean": 0.10782833728703903, + "variance": 0.05417295817584507, + "sd": 0.2327508500002633, + "sem": 0.003418005267995262, + "df": 4636, + "critical": 1.96, + "moe": 0.006699290325270713, + "p75": 0.10000038146972656, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 2.3000001907348633, + "sampleCount": 4637, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 5.6491409731405895, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 9.199999809265137, + "hz": 9384.123186102057, + "period": 0.10656296599782557, + "mean": 0.10656296599782557, + "variance": 0.04427064366559609, + "sd": 0.21040590216435492, + "sem": 0.003071373558355632, + "df": 4692, + "critical": 1.96, + "moe": 0.006019892174377039, + "p75": 0.10000038146972656, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 2.1999998092651367, + "sampleCount": 4693, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 14.717259413505085, + "samples": [], + "totalTime": 500.0000009536743, + "min": 0, + "max": 35.09999990463257, + "hz": 8889.99998304367, + "period": 0.11248593947214271, + "mean": 0.11248593947214271, + "variance": 0.31711003996544773, + "sd": 0.5631252435874703, + "sem": 0.008446350773384466, + "df": 4444, + "critical": 1.96, + "moe": 0.016554847515833554, + "p75": 0.10000038146972656, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 0.9000000953674316, + "sampleCount": 4445, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 68.2052681493694, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 174.09999990463257, + "hz": 6278.744258333785, + "period": 0.15926751574133613, + "mean": 0.15926751574133613, + "variance": 9.645122740701863, + "sd": 3.105659791526088, + "sem": 0.05542287560521298, + "df": 3139, + "critical": 1.96, + "moe": 0.10862883618621744, + "p75": 0.10000038146972656, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 0.20000028610229492, + "sampleCount": 3140, + "median": 0.09999990463256836 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 18.43186588590383, + "samples": [], + "totalTime": 507.0999994277954, + "min": 0, + "max": 32.90000009536743, + "hz": 11589.430105761241, + "period": 0.08628551972567558, + "mean": 0.08628551972567558, + "variance": 0.38695279696225127, + "sd": 0.6220553005659957, + "sem": 0.008114301670812049, + "df": 5876, + "critical": 1.96, + "moe": 0.015904031274791616, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 8.5, + "sampleCount": 5877, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 0.41400540987177387, + "samples": [], + "totalTime": 500.3999996185303, + "min": 4, + "max": 4.700000286102295, + "hz": 221.82254213552875, + "period": 4.508108104671444, + "mean": 4.508108104671444, + "variance": 0.009842747737513783, + "sd": 0.09921062310818224, + "sem": 0.009416655618671882, + "df": 110, + "critical": 1.982, + "moe": 0.01866381143620767, + "p75": 4.599999904632568, + "p99": 4.600000381469727, + "p995": 4.700000286102295, + "p999": 4.700000286102295, + "sampleCount": 111, + "median": 4.5 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 1.407704313748449, + "samples": [], + "totalTime": 1088.1999998092651, + "min": 107.40000009536743, + "max": 113, + "hz": 9.189487228223447, + "period": 108.81999998092651, + "mean": 108.81999998092651, + "variance": 4.586222543080677, + "sd": 2.141546764159185, + "sem": 0.6772165490506472, + "df": 9, + "critical": 2.262, + "moe": 1.531863833952564, + "p75": 108.2999997138977, + "p99": 113, + "p995": 113, + "p999": 113, + "sampleCount": 10, + "median": 107.90000009536743 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 10.805071640743629, + "samples": [], + "totalTime": 509.1000003814697, + "min": 0.2999997138977051, + "max": 9.900000095367432, + "hz": 1832.6458442366945, + "period": 0.5456591643960018, + "mean": 0.5456591643960018, + "variance": 0.8442434691286086, + "sd": 0.918827224851663, + "sem": 0.030081052871056658, + "df": 932, + "critical": 1.96, + "moe": 0.05895886362727105, + "p75": 0.5, + "p99": 8, + "p995": 9.5, + "p999": 9.900000095367432, + "sampleCount": 933, + "median": 0.40000009536743164 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 0.28188285467806945, + "samples": [], + "totalTime": 504.1000003814697, + "min": 4.299999713897705, + "max": 4.700000286102295, + "hz": 220.19440570522218, + "period": 4.541441444878106, + "mean": 4.541441444878106, + "variance": 0.004630633811131108, + "sd": 0.068048760540741, + "sem": 0.006458902516829146, + "df": 110, + "critical": 1.982, + "moe": 0.012801544788355367, + "p75": 4.599999904632568, + "p99": 4.699999809265137, + "p995": 4.700000286102295, + "p999": 4.700000286102295, + "sampleCount": 111, + "median": 4.5 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.8454988126471945, + "samples": [], + "totalTime": 1120.8000001907349, + "min": 109.90000009536743, + "max": 118.39999961853027, + "hz": 8.92219842817472, + "period": 112.08000001907348, + "mean": 112.08000001907348, + "variance": 8.361777049594508, + "sd": 2.8916737453583017, + "sem": 0.9144275285441984, + "df": 9, + "critical": 2.262, + "moe": 2.0684350695669766, + "p75": 111.30000019073486, + "p99": 118.39999961853027, + "p995": 118.39999961853027, + "p999": 118.39999961853027, + "sampleCount": 10, + "median": 110.85000014305115 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 2, + "rme": 83.97649615375717, + "samples": [], + "totalTime": 698.5, + "min": 2.3999996185302734, + "max": 290.5, + "hz": 157.48031496062993, + "period": 6.35, + "mean": 6.35, + "variance": 796.0872939814996, + "sd": 28.21501894349, + "sem": 2.6901965017473413, + "df": 109, + "critical": 1.9822, + "moe": 5.33250750576358, + "p75": 2.799999713897705, + "p99": 72.7000002861023, + "p995": 290.5, + "p999": 290.5, + "sampleCount": 110, + "median": 2.5999999046325684 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 1, + "rme": 0.304357326026443, + "samples": [], + "totalTime": 504.49999952316284, + "min": 4.299999713897705, + "max": 4.699999809265137, + "hz": 220.0198218135057, + "period": 4.545045040749215, + "mean": 4.545045040749215, + "variance": 0.005407039982895738, + "sd": 0.07353257769788665, + "sem": 0.0069794034070241005, + "df": 110, + "critical": 1.982, + "moe": 0.013833177552721768, + "p75": 4.599999904632568, + "p99": 4.699999809265137, + "p995": 4.699999809265137, + "p999": 4.699999809265137, + "sampleCount": 111, + "median": 4.5 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 0.4994315964961712, + "samples": [], + "totalTime": 1117.6999998092651, + "min": 110.80000019073486, + "max": 113.5, + "hz": 8.946944619939602, + "period": 111.76999998092651, + "mean": 111.76999998092651, + "variance": 0.609000051710407, + "sd": 0.78038455373643, + "sem": 0.24677926406211825, + "df": 9, + "critical": 2.262, + "moe": 0.5582146953085115, + "p75": 112.10000038146973, + "p99": 113.5, + "p995": 113.5, + "p999": 113.5, + "sampleCount": 10, + "median": 111.65000009536743 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 1, + "rme": 19.284348761690524, + "samples": [], + "totalTime": 504.7000002861023, + "min": 5.800000190734863, + "max": 46.30000019073486, + "hz": 103.0315038052753, + "period": 9.705769236271198, + "mean": 9.705769236271198, + "variance": 45.17545635435559, + "sd": 6.721268954174917, + "sem": 0.9320723019408418, + "df": 51, + "critical": 2.0081, + "moe": 1.8716943895274045, + "p75": 8.800000190734863, + "p99": 46.30000019073486, + "p995": 46.30000019073486, + "p999": 46.30000019073486, + "sampleCount": 52, + "median": 6.900000095367432 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 2, + "rme": 202.4803847640316, + "samples": [], + "totalTime": 1734.4000000953674, + "min": 4.5, + "max": 1661.0999999046326, + "hz": 9.801660516066214, + "period": 102.02352941737456, + "mean": 102.02352941737456, + "variance": 161414.96689085753, + "sd": 401.76481539684073, + "sem": 97.4422806198797, + "df": 16, + "critical": 2.12, + "moe": 206.57763491414497, + "p75": 4.600000381469727, + "p99": 1661.0999999046326, + "p995": 1661.0999999046326, + "p999": 1661.0999999046326, + "sampleCount": 17, + "median": 4.599999904632568 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.2588941695711398, + "samples": [], + "totalTime": 1253.9000000953674, + "min": 121.59999990463257, + "max": 128.69999980926514, + "hz": 7.975117632378526, + "period": 125.39000000953675, + "mean": 125.39000000953675, + "variance": 4.869888838238242, + "sd": 2.2067824628264203, + "sem": 0.6978458883047346, + "df": 9, + "critical": 2.262, + "moe": 1.5785273993453097, + "p75": 126.7000002861023, + "p99": 128.69999980926514, + "p995": 128.69999980926514, + "p999": 128.69999980926514, + "sampleCount": 10, + "median": 125.9500002861023 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 1.224259211248794, + "samples": [], + "totalTime": 500.2999997138977, + "min": 3, + "max": 5.599999904632568, + "hz": 305.8165102688283, + "period": 3.269934638652926, + "mean": 3.269934638652926, + "variance": 0.06382696475370132, + "sd": 0.25263999040868673, + "sem": 0.020424732660981337, + "df": 152, + "critical": 1.96, + "moe": 0.04003247601552342, + "p75": 3.3000001907348633, + "p99": 4.299999713897705, + "p995": 5.599999904632568, + "p999": 5.599999904632568, + "sampleCount": 153, + "median": 3.200000286102295 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 5.478866850296287, + "samples": [], + "totalTime": 504.09999990463257, + "min": 18.699999809265137, + "max": 31.199999809265137, + "hz": 47.60960127859632, + "period": 21.004166662693024, + "mean": 21.004166662693024, + "variance": 7.424764171856074, + "sd": 2.7248420453039244, + "sem": 0.5562060533896916, + "df": 23, + "critical": 2.069, + "moe": 1.150790324463272, + "p75": 20.699999809265137, + "p99": 31.199999809265137, + "p995": 31.199999809265137, + "p999": 31.199999809265137, + "sampleCount": 24, + "median": 20 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 13.332074753075368, + "samples": [], + "totalTime": 861.4000000953674, + "min": 78.40000009536743, + "max": 130.69999980926514, + "hz": 11.609008589381098, + "period": 86.14000000953675, + "mean": 86.14000000953675, + "variance": 257.7626654112075, + "sd": 16.054988801341704, + "sem": 5.077033242073638, + "df": 9, + "critical": 2.262, + "moe": 11.484249193570568, + "p75": 83.30000019073486, + "p99": 130.69999980926514, + "p995": 130.69999980926514, + "p999": 130.69999980926514, + "sampleCount": 10, + "median": 79.84999990463257 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 15.528266674705533, + "samples": [], + "totalTime": 3840.8999996185303, + "min": 346.59999990463257, + "max": 619.8999996185303, + "hz": 2.603556458380374, + "period": 384.08999996185304, + "mean": 384.08999996185304, + "variance": 6952.272091095819, + "sd": 83.38028598593206, + "sem": 26.367161567176353, + "df": 9, + "critical": 2.262, + "moe": 59.64251946495291, + "p75": 370.7000002861023, + "p99": 619.8999996185303, + "p995": 619.8999996185303, + "p999": 619.8999996185303, + "sampleCount": 10, + "median": 355.2999999523163 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.8437186848665077, + "samples": [], + "totalTime": 500.09999990463257, + "min": 4.099999904632568, + "max": 5.400000095367432, + "hz": 207.9584083579933, + "period": 4.808653845236852, + "mean": 4.808653845236852, + "variance": 0.04351661300556835, + "sd": 0.2086063589768259, + "sem": 0.02045553644389186, + "df": 103, + "critical": 1.9834, + "moe": 0.04057151098281512, + "p75": 4.900000095367432, + "p99": 5.300000190734863, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 104, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.7206392580907492, + "samples": [], + "totalTime": 503.2999997138977, + "min": 4.399999618530273, + "max": 5.300000190734863, + "hz": 202.6624280905666, + "period": 4.934313722685272, + "mean": 4.934313722685272, + "variance": 0.03277130617031419, + "sd": 0.18102846784501656, + "sem": 0.017924489264557503, + "df": 101, + "critical": 1.9838, + "moe": 0.03555860180302917, + "p75": 5, + "p99": 5.300000190734863, + "p995": 5.300000190734863, + "p999": 5.300000190734863, + "sampleCount": 102, + "median": 4.950000047683716 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 1.2111983358909018, + "samples": [], + "totalTime": 503.7999997138977, + "min": 4.199999809265137, + "max": 5.599999904632568, + "hz": 200.47637962952908, + "period": 4.988118809048492, + "mean": 4.988118809048492, + "variance": 0.09365741079731521, + "sd": 0.30603498296324755, + "sem": 0.030451618955371174, + "df": 100, + "critical": 1.984, + "moe": 0.06041601200745641, + "p75": 5.199999809265137, + "p99": 5.5, + "p995": 5.599999904632568, + "p999": 5.599999904632568, + "sampleCount": 101, + "median": 5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 1.5706485046523304, + "samples": [], + "totalTime": 503.19999980926514, + "min": 4.199999809265137, + "max": 5.800000190734863, + "hz": 206.67726557913466, + "period": 4.838461536627549, + "mean": 4.838461536627549, + "variance": 0.15268111322248482, + "sd": 0.3907443067051455, + "sem": 0.038315631629131174, + "df": 103, + "critical": 1.9834, + "moe": 0.07599522377321877, + "p75": 5.099999904632568, + "p99": 5.5, + "p995": 5.800000190734863, + "p999": 5.800000190734863, + "sampleCount": 104, + "median": 5 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 3, + "rme": 3.208094611879432, + "samples": [], + "totalTime": 504, + "min": 5, + "max": 12.700000286102295, + "hz": 178.57142857142858, + "period": 5.6, + "mean": 5.6, + "variance": 0.7355056852705417, + "sd": 0.8576162809033779, + "sem": 0.09040069353658138, + "df": 89, + "critical": 1.9873, + "moe": 0.17965329826524817, + "p75": 5.800000190734863, + "p99": 12.700000286102295, + "p995": 12.700000286102295, + "p999": 12.700000286102295, + "sampleCount": 90, + "median": 5.3500001430511475 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 2, + "rme": 2.1824996338052416, + "samples": [], + "totalTime": 501.4000005722046, + "min": 4.900000095367432, + "max": 9.5, + "hz": 183.48623832271306, + "period": 5.450000006219615, + "mean": 5.450000006219615, + "variance": 0.3297802237626304, + "sd": 0.5742649421326627, + "sem": 0.059871258961156054, + "df": 91, + "critical": 1.9867, + "moe": 0.11894623017812873, + "p75": 5.699999809265137, + "p99": 9.5, + "p995": 9.5, + "p999": 9.5, + "sampleCount": 92, + "median": 5.299999713897705 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 1.545695802042916, + "samples": [], + "totalTime": 501.5, + "min": 4.900000095367432, + "max": 6.799999713897705, + "hz": 185.44366899302094, + "period": 5.39247311827957, + "mean": 5.39247311827957, + "variance": 0.1637470813910293, + "sd": 0.4046567451446093, + "sem": 0.04196094976618004, + "df": 92, + "critical": 1.9864, + "moe": 0.08335123061554003, + "p75": 5.699999809265137, + "p99": 6.799999713897705, + "p995": 6.799999713897705, + "p999": 6.799999713897705, + "sampleCount": 93, + "median": 5.200000286102295 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 10.128455235986863, + "samples": [], + "totalTime": 508.69999980926514, + "min": 9.099999904632568, + "max": 35, + "hz": 100.25555340892909, + "period": 9.97450980018167, + "mean": 9.97450980018167, + "variance": 12.896737234871093, + "sd": 3.5912027560235433, + "sem": 0.5028689696966268, + "df": 50, + "critical": 2.009, + "moe": 1.010263760120523, + "p75": 9.599999904632568, + "p99": 35, + "p995": 35, + "p999": 35, + "sampleCount": 51, + "median": 9.400000095367432 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 1.9668562422605107, + "samples": [], + "totalTime": 505.19999980926514, + "min": 8.199999809265137, + "max": 11.099999904632568, + "hz": 110.84718927383695, + "period": 9.021428568022591, + "mean": 9.021428568022591, + "variance": 0.4388052067447292, + "sd": 0.6624237365498984, + "sem": 0.08852009525129724, + "df": 55, + "critical": 2.0045, + "moe": 0.17743853093122533, + "p75": 9.400000095367432, + "p99": 11.099999904632568, + "p995": 11.099999904632568, + "p999": 11.099999904632568, + "sampleCount": 56, + "median": 8.800000190734863 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 63.20030947172104, + "samples": [], + "totalTime": 511.90000009536743, + "min": 18.59999990463257, + "max": 173.59999990463257, + "hz": 33.20961124601072, + "period": 30.111764711492203, + "mean": 30.111764711492203, + "variance": 1369.8973507976532, + "sd": 37.01212437563741, + "sem": 8.976758719367716, + "df": 16, + "critical": 2.12, + "moe": 19.03072848505956, + "p75": 22.199999809265137, + "p99": 173.59999990463257, + "p995": 173.59999990463257, + "p999": 173.59999990463257, + "sampleCount": 17, + "median": 21.100000381469727 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 6.1926986148534455, + "samples": [], + "totalTime": 509.59999990463257, + "min": 26.800000190734863, + "max": 39, + "hz": 31.397174260192834, + "period": 31.849999994039536, + "mean": 31.849999994039536, + "variance": 13.70666647275291, + "sd": 3.7022515409886605, + "sem": 0.9255628852471651, + "df": 15, + "critical": 2.131, + "moe": 1.9723745084617086, + "p75": 32.5, + "p99": 39, + "p995": 39, + "p999": 39, + "sampleCount": 16, + "median": 31.40000009536743 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 7.022188767546911, + "samples": [], + "totalTime": 500.90000009536743, + "min": 37.19999980926514, + "max": 49.59999990463257, + "hz": 23.956877615722288, + "period": 41.74166667461395, + "mean": 41.74166667461395, + "variance": 21.282651422529526, + "sd": 4.613312413280671, + "sem": 1.3317485818317187, + "df": 11, + "critical": 2.201, + "moe": 2.931178628611613, + "p75": 43.40000009536743, + "p99": 49.59999990463257, + "p995": 49.59999990463257, + "p999": 49.59999990463257, + "sampleCount": 12, + "median": 41 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 0.8035273997443196, + "samples": [], + "totalTime": 504.30000019073486, + "min": 4.5, + "max": 5.400000095367432, + "hz": 202.26055911445937, + "period": 4.944117648928773, + "mean": 4.944117648928773, + "variance": 0.040905657153423876, + "sd": 0.20225147008964825, + "sem": 0.020025879617268556, + "df": 101, + "critical": 1.9838, + "moe": 0.03972733998473736, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 102, + "median": 4.900000095367432 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.4619615887285295, + "samples": [], + "totalTime": 502.40000009536743, + "min": 5.400000095367432, + "max": 7.099999904632568, + "hz": 165.20700633806652, + "period": 6.053012049341777, + "mean": 6.053012049341777, + "variance": 0.16422862865911989, + "sd": 0.4052513154316959, + "sem": 0.04448211074820868, + "df": 82, + "critical": 1.9894, + "moe": 0.08849271112248636, + "p75": 6.400000095367432, + "p99": 7.099999904632568, + "p995": 7.099999904632568, + "p999": 7.099999904632568, + "sampleCount": 83, + "median": 6 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.966255506572364, + "samples": [], + "totalTime": 503.40000009536743, + "min": 0.09999990463256836, + "max": 5.700000286102295, + "hz": 206.5951529207341, + "period": 4.84038461630161, + "mean": 4.84038461630161, + "variance": 1.5276736391899728, + "sd": 1.2359909543317753, + "sem": 0.12119888451465176, + "df": 103, + "critical": 1.9834, + "moe": 0.2403858675463603, + "p75": 5.599999904632568, + "p99": 5.700000286102295, + "p995": 5.700000286102295, + "p999": 5.700000286102295, + "sampleCount": 104, + "median": 4.8999998569488525 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.7300799233118649, + "samples": [], + "totalTime": 502.7000002861023, + "min": 3.9000000953674316, + "max": 5.799999713897705, + "hz": 212.85060660255215, + "period": 4.698130843795348, + "mean": 4.698130843795348, + "variance": 0.1798077909910312, + "sd": 0.42403748771898836, + "sem": 0.040993251210119847, + "df": 106, + "critical": 1.9828, + "moe": 0.08128141849942563, + "p75": 5.099999904632568, + "p99": 5.300000190734863, + "p995": 5.799999713897705, + "p999": 5.799999713897705, + "sampleCount": 107, + "median": 4.800000190734863 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 4.460881943755258, + "samples": [], + "totalTime": 510.40000009536743, + "min": 12.900000095367432, + "max": 21, + "hz": 70.53291534732261, + "period": 14.177777780426872, + "mean": 14.177777780426872, + "variance": 3.4892062141781994, + "sd": 1.867941705240878, + "sem": 0.3113236175401463, + "df": 35, + "critical": 2.0315, + "moe": 0.6324539290328072, + "p75": 14.300000190734863, + "p99": 21, + "p995": 21, + "p999": 21, + "sampleCount": 36, + "median": 13.549999952316284 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 26.50031388865704, + "samples": [], + "totalTime": 500.69999980926514, + "min": 0.7999997138977051, + "max": 71, + "hz": 171.75953671412128, + "period": 5.822093021037967, + "mean": 5.822093021037967, + "variance": 51.773506137874016, + "sd": 7.195380889006087, + "sem": 0.7758978755165484, + "df": 85, + "critical": 1.9885, + "moe": 1.5428729254646565, + "p75": 5.400000095367432, + "p99": 71, + "p995": 71, + "p999": 71, + "sampleCount": 86, + "median": 5.199999809265137 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 3.7036413914676136, + "samples": [], + "totalTime": 500.5, + "min": 4.799999713897705, + "max": 10.700000286102295, + "hz": 177.82217782217782, + "period": 5.623595505617978, + "mean": 5.623595505617978, + "variance": 0.9772778126338978, + "sd": 0.9885736252975282, + "sem": 0.10478859470455817, + "df": 88, + "critical": 1.9876, + "moe": 0.20827781083477984, + "p75": 5.699999809265137, + "p99": 10.700000286102295, + "p995": 10.700000286102295, + "p999": 10.700000286102295, + "sampleCount": 89, + "median": 5.400000095367432 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 10.14637444425631, + "samples": [], + "totalTime": 573.5, + "min": 48.90000009536743, + "max": 75.80000019073486, + "hz": 19.18047079337402, + "period": 52.13636363636363, + "mean": 52.13636363636363, + "variance": 62.01054631094503, + "sd": 7.874677536950007, + "sem": 2.3743046122821085, + "df": 10, + "critical": 2.228, + "moe": 5.289950676164539, + "p75": 50.59999990463257, + "p99": 75.80000019073486, + "p995": 75.80000019073486, + "p999": 75.80000019073486, + "sampleCount": 11, + "median": 50 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 7.764805542625558, + "samples": [], + "totalTime": 502.5, + "min": 4, + "max": 24.299999713897705, + "hz": 115.42288557213931, + "period": 8.663793103448276, + "mean": 8.663793103448276, + "variance": 6.5444553784522554, + "sd": 2.5582133176207678, + "sem": 0.3359098652310194, + "df": 57, + "critical": 2.0027, + "moe": 0.6727266870981625, + "p75": 9, + "p99": 24.299999713897705, + "p995": 24.299999713897705, + "p999": 24.299999713897705, + "sampleCount": 58, + "median": 8.400000095367432 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 10.632659804284065, + "samples": [], + "totalTime": 518, + "min": 28.300000190734863, + "max": 55.69999980926514, + "hz": 30.888030888030887, + "period": 32.375, + "mean": 32.375, + "variance": 41.74999951680505, + "sd": 6.461423954269295, + "sem": 1.6153559885673237, + "df": 15, + "critical": 2.131, + "moe": 3.4423236116369664, + "p75": 31.40000009536743, + "p99": 55.69999980926514, + "p995": 55.69999980926514, + "p999": 55.69999980926514, + "sampleCount": 16, + "median": 30.649999856948853 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 16.88679866466988, + "samples": [], + "totalTime": 2277.199999332428, + "min": 196.89999961853027, + "max": 376.3999996185303, + "hz": 4.39135780912153, + "period": 227.7199999332428, + "mean": 227.7199999332428, + "variance": 2890.092878151364, + "sd": 53.75958405857847, + "sem": 17.00027316883868, + "df": 9, + "critical": 2.262, + "moe": 38.4546179079131, + "p75": 224.09999990463257, + "p99": 376.3999996185303, + "p995": 376.3999996185303, + "p999": 376.3999996185303, + "sampleCount": 10, + "median": 211.29999995231628 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 176.74014235393187, + "samples": [], + "totalTime": 1798.0999999046326, + "min": 34.40000009536743, + "max": 1444.0999999046326, + "hz": 5.561425949908447, + "period": 179.80999999046327, + "mean": 179.80999999046327, + "variance": 197384.42541764432, + "sd": 444.2796702727285, + "sem": 140.4935676170423, + "df": 9, + "critical": 2.262, + "moe": 317.7964499497497, + "p75": 41, + "p99": 1444.0999999046326, + "p995": 1444.0999999046326, + "p999": 1444.0999999046326, + "sampleCount": 10, + "median": 37.69999980926514 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/dm-idb-prev.json b/bench-results/dm-idb-prev.json new file mode 100644 index 000000000..2940e6b80 --- /dev/null +++ b/bench-results/dm-idb-prev.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 54.50622258173367, + "samples": [], + "totalTime": 501.90000009536743, + "min": 0, + "max": 139.59999990463257, + "hz": 5437.338114129219, + "period": 0.18391352147136952, + "mean": 0.18391352147136952, + "variance": 7.138564433903858, + "sd": 2.6718092061193026, + "sem": 0.051145057842392455, + "df": 2728, + "critical": 1.96, + "moe": 0.10024431337108922, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.40000009536743164, + "sampleCount": 2729, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 13.249307690921338, + "samples": [], + "totalTime": 500.00000047683716, + "min": 0, + "max": 33.69999980926514, + "hz": 7207.999993125915, + "period": 0.1387347393109981, + "mean": 0.1387347393109981, + "variance": 0.3169782448203781, + "sd": 0.5630082102601863, + "sem": 0.009378261472199868, + "df": 3603, + "critical": 1.96, + "moe": 0.018381392485511742, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.3000001907348633, + "sampleCount": 3604, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 49.94193862437275, + "samples": [], + "totalTime": 500.09999990463257, + "min": 0, + "max": 127.5, + "hz": 5740.851830728835, + "period": 0.174190177605236, + "mean": 0.174190177605236, + "variance": 5.6558667214879685, + "sd": 2.378206618754554, + "sem": 0.044384669178210635, + "df": 2870, + "critical": 1.96, + "moe": 0.08699395158929285, + "p75": 0.19999980926513672, + "p99": 0.20000028610229492, + "p995": 0.3000001907348633, + "p999": 0.40000009536743164, + "sampleCount": 2871, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 225.64307967783276, + "samples": [], + "totalTime": 631.8000001907349, + "min": 0.09999990463256836, + "max": 630.4000000953674, + "hz": 15.827793600793111, + "period": 63.18000001907349, + "mean": 63.18000001907349, + "variance": 39720.80845513915, + "sd": 199.30079893251596, + "sem": 63.02444641180052, + "df": 9, + "critical": 2.262, + "moe": 142.56129778349276, + "p75": 0.20000028610229492, + "p99": 630.4000000953674, + "p995": 630.4000000953674, + "p999": 630.4000000953674, + "sampleCount": 10, + "median": 0.19999980926513672 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 9.579448003266005, + "samples": [], + "totalTime": 500.0000023841858, + "min": 0, + "max": 20.800000190734863, + "hz": 15473.99992621422, + "period": 0.0646245317803006, + "mean": 0.0646245317803006, + "variance": 0.07718559247145353, + "sd": 0.27782295166428117, + "sem": 0.003158506846555108, + "df": 7736, + "critical": 1.96, + "moe": 0.006190673419248011, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 0.40000009536743164, + "sampleCount": 7737, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 0.6199738249330471, + "samples": [], + "totalTime": 503.09999990463257, + "min": 4, + "max": 4.800000190734863, + "hz": 218.6444047323625, + "period": 4.573636362769387, + "mean": 4.573636362769387, + "variance": 0.022509596704574013, + "sd": 0.15003198560498363, + "sem": 0.014304988546458512, + "df": 109, + "critical": 1.9822, + "moe": 0.02835534829679006, + "p75": 4.600000381469727, + "p99": 4.800000190734863, + "p995": 4.800000190734863, + "p999": 4.800000190734863, + "sampleCount": 110, + "median": 4.599999904632568 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 2.3397265581246294, + "samples": [], + "totalTime": 1133.7000002861023, + "min": 109.2000002861023, + "max": 119.80000019073486, + "hz": 8.820675661529844, + "period": 113.37000002861024, + "mean": 113.37000002861024, + "variance": 13.75122226651512, + "sd": 3.708264050268686, + "sem": 1.1726560564170176, + "df": 9, + "critical": 2.262, + "moe": 2.652547999615294, + "p75": 116.09999990463257, + "p99": 119.80000019073486, + "p995": 119.80000019073486, + "p999": 119.80000019073486, + "sampleCount": 10, + "median": 112.04999995231628 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 9.45685950813143, + "samples": [], + "totalTime": 500.00000190734863, + "min": 0.10000038146972656, + "max": 20.899999618530273, + "hz": 2823.999989227295, + "period": 0.35410765007602596, + "mean": 0.35410765007602596, + "variance": 0.412180125271523, + "sd": 0.6420125584998497, + "sem": 0.017085440293487467, + "df": 1411, + "critical": 1.96, + "moe": 0.03348746297523544, + "p75": 0.3000001907348633, + "p99": 1.0999999046325684, + "p995": 1.3999996185302734, + "p999": 9.799999713897705, + "sampleCount": 1412, + "median": 0.3000001907348633 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 1.9133023415925396, + "samples": [], + "totalTime": 500.19999980926514, + "min": 4, + "max": 8.5, + "hz": 221.91123559041625, + "period": 4.506306304587974, + "mean": 4.506306304587974, + "variance": 0.21005078136719008, + "sd": 0.4583129731604704, + "sem": 0.0435011423032361, + "df": 110, + "critical": 1.982, + "moe": 0.08621926404501395, + "p75": 4.599999904632568, + "p99": 5, + "p995": 8.5, + "p999": 8.5, + "sampleCount": 111, + "median": 4.599999904632568 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.0074849892867523, + "samples": [], + "totalTime": 1176.6999998092651, + "min": 115.80000019073486, + "max": 120.2999997138977, + "hz": 8.498342824527008, + "period": 117.66999998092652, + "mean": 117.66999998092652, + "variance": 2.7467774543762564, + "sd": 1.6573404762981734, + "sem": 0.5240970763490534, + "df": 9, + "critical": 2.262, + "moe": 1.185507586701559, + "p75": 119.09999990463257, + "p99": 120.2999997138977, + "p995": 120.2999997138977, + "p999": 120.2999997138977, + "sampleCount": 10, + "median": 117.25 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 9.169789243545004, + "samples": [], + "totalTime": 518.5999984741211, + "min": 1.0999999046325684, + "max": 20.90000009536743, + "hz": 659.467799857825, + "period": 1.5163742645442138, + "mean": 1.5163742645442138, + "variance": 1.7212560574977103, + "sd": 1.3119664848987989, + "sem": 0.07094302255207142, + "df": 341, + "critical": 1.96, + "moe": 0.13904832420205998, + "p75": 1.4000000953674316, + "p99": 5.700000286102295, + "p995": 11.300000190734863, + "p999": 20.90000009536743, + "sampleCount": 342, + "median": 1.2999999523162842 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 10.732844424147734, + "samples": [], + "totalTime": 503.40000009536743, + "min": 3.8999996185302734, + "max": 31.300000190734863, + "hz": 218.51410405077647, + "period": 4.576363637230613, + "mean": 4.576363637230613, + "variance": 6.754115174698401, + "sd": 2.5988680564234885, + "sem": 0.24779234661851995, + "df": 109, + "critical": 1.9822, + "moe": 0.49117398946723023, + "p75": 4.699999809265137, + "p99": 5.199999809265137, + "p995": 31.300000190734863, + "p999": 31.300000190734863, + "sampleCount": 110, + "median": 4.150000095367432 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 2.078810225257847, + "samples": [], + "totalTime": 1210.3999996185303, + "min": 118.09999990463257, + "max": 128.90000009536743, + "hz": 8.261731661559486, + "period": 121.03999996185303, + "mean": 121.03999996185303, + "variance": 12.373777923160155, + "sd": 3.5176381171405557, + "sem": 1.112374843439034, + "df": 9, + "critical": 2.262, + "moe": 2.5161918958590945, + "p75": 123.30000019073486, + "p99": 128.90000009536743, + "p995": 128.90000009536743, + "p999": 128.90000009536743, + "sampleCount": 10, + "median": 119.65000009536743 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 6.488207703160261, + "samples": [], + "totalTime": 502.1999988555908, + "min": 6.5, + "max": 22.09999990463257, + "hz": 121.46555184987314, + "period": 8.232786866485096, + "mean": 8.232786866485096, + "variance": 4.351240387864485, + "sd": 2.08596270049694, + "sem": 0.26708015582802613, + "df": 60, + "critical": 2, + "moe": 0.5341603116560523, + "p75": 8.5, + "p99": 22.09999990463257, + "p995": 22.09999990463257, + "p999": 22.09999990463257, + "sampleCount": 61, + "median": 7.699999809265137 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 1.3781958879879457, + "samples": [], + "totalTime": 504, + "min": 4, + "max": 5.200000286102295, + "hz": 228.1746031746032, + "period": 4.3826086956521735, + "mean": 4.3826086956521735, + "variance": 0.10688788741352917, + "sd": 0.3269371306742768, + "sem": 0.03048704463460549, + "df": 114, + "critical": 1.9812, + "moe": 0.0604009328300804, + "p75": 4.599999904632568, + "p99": 5.200000286102295, + "p995": 5.200000286102295, + "p999": 5.200000286102295, + "sampleCount": 115, + "median": 4.299999713897705 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 2.488276067909993, + "samples": [], + "totalTime": 1215.9000000953674, + "min": 115.59999990463257, + "max": 129.09999990463257, + "hz": 8.224360555321708, + "period": 121.59000000953674, + "mean": 121.59000000953674, + "variance": 17.889888793733412, + "sd": 4.229644050476756, + "sem": 1.3375308891286741, + "df": 9, + "critical": 2.262, + "moe": 3.025494871209061, + "p75": 122.7000002861023, + "p99": 129.09999990463257, + "p995": 129.09999990463257, + "p999": 129.09999990463257, + "sampleCount": 10, + "median": 120.54999995231628 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 106.67520880993533, + "samples": [], + "totalTime": 502.8999996185303, + "min": 3.299999713897705, + "max": 272.1000003814697, + "hz": 129.25034807974765, + "period": 7.736923071054312, + "mean": 7.736923071054312, + "variance": 1109.1389311227797, + "sd": 33.303737494803485, + "sem": 4.130820240996621, + "df": 64, + "critical": 1.998, + "moe": 8.253378841511248, + "p75": 3.6000003814697266, + "p99": 272.1000003814697, + "p995": 272.1000003814697, + "p999": 272.1000003814697, + "sampleCount": 65, + "median": 3.5 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 3.0317992326491705, + "samples": [], + "totalTime": 515.7000002861023, + "min": 20.5, + "max": 26.90000009536743, + "hz": 44.599573370641764, + "period": 22.421739142874014, + "mean": 22.421739142874014, + "variance": 2.470869454545972, + "sd": 1.5718999505521882, + "sem": 0.32776379714573434, + "df": 22, + "critical": 2.074, + "moe": 0.679782115280253, + "p75": 22.800000190734863, + "p99": 26.90000009536743, + "p995": 26.90000009536743, + "p999": 26.90000009536743, + "sampleCount": 23, + "median": 22.199999809265137 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 5.101646977386887, + "samples": [], + "totalTime": 899.9999995231628, + "min": 86.30000019073486, + "max": 107.39999961853027, + "hz": 11.11111111699799, + "period": 89.99999995231629, + "mean": 89.99999995231629, + "variance": 41.20222063912289, + "sd": 6.418895593411914, + "sem": 2.029833013799975, + "df": 9, + "critical": 2.262, + "moe": 4.591482277215543, + "p75": 90.09999990463257, + "p99": 107.39999961853027, + "p995": 107.39999961853027, + "p999": 107.39999961853027, + "sampleCount": 10, + "median": 87.45000004768372 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 14.883070638564389, + "samples": [], + "totalTime": 4130.39999961853, + "min": 373.40000009536743, + "max": 655.8999996185303, + "hz": 2.4210730197858723, + "period": 413.039999961853, + "mean": 413.039999961853, + "variance": 7385.571533166674, + "sd": 85.93934799128205, + "sem": 27.17640802822675, + "df": 9, + "critical": 2.262, + "moe": 61.47303495984891, + "p75": 393.2999997138977, + "p99": 655.8999996185303, + "p995": 655.8999996185303, + "p999": 655.8999996185303, + "sampleCount": 10, + "median": 384 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.32406339987359434, + "samples": [], + "totalTime": 504.5999994277954, + "min": 4.5, + "max": 5, + "hz": 210.0673803412634, + "period": 4.76037735309241, + "mean": 4.76037735309241, + "variance": 0.00641509608764699, + "sd": 0.08009429497565347, + "sem": 0.007779445636532467, + "df": 105, + "critical": 1.983, + "moe": 0.015426640697243883, + "p75": 4.800000190734863, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 106, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.4198453715860097, + "samples": [], + "totalTime": 502.6000003814697, + "min": 4.5, + "max": 5, + "hz": 208.9136488665057, + "period": 4.786666670299712, + "mean": 4.786666670299712, + "variance": 0.010782051013112564, + "sd": 0.1038366554407092, + "sem": 0.010133419961931981, + "df": 104, + "critical": 1.9832, + "moe": 0.020096598468503507, + "p75": 4.899999618530273, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 105, + "median": 4.800000190734863 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 0.39727582120239235, + "samples": [], + "totalTime": 500, + "min": 4.599999904632568, + "max": 5.099999904632568, + "hz": 202, + "period": 4.9504950495049505, + "mean": 4.9504950495049505, + "variance": 0.009924749804973446, + "sd": 0.09962303852509943, + "sem": 0.009912862833419644, + "df": 100, + "critical": 1.984, + "moe": 0.019667119861504573, + "p75": 5, + "p99": 5.099999904632568, + "p995": 5.099999904632568, + "p999": 5.099999904632568, + "sampleCount": 101, + "median": 5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 0.6761934850014394, + "samples": [], + "totalTime": 500, + "min": 4.399999618530273, + "max": 5.699999809265137, + "hz": 218, + "period": 4.587155963302752, + "mean": 4.587155963302752, + "variance": 0.026685349605080115, + "sd": 0.1633565107520362, + "sem": 0.01564671598603119, + "df": 108, + "critical": 1.9824, + "moe": 0.03101804977070823, + "p75": 4.600000381469727, + "p99": 5.099999904632568, + "p995": 5.699999809265137, + "p999": 5.699999809265137, + "sampleCount": 109, + "median": 4.599999904632568 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 3, + "rme": 86.11279758461367, + "samples": [], + "totalTime": 854.4000000953674, + "min": 5.699999809265137, + "max": 375.59999990463257, + "hz": 92.46254680615881, + "period": 10.815189874624904, + "mean": 10.815189874624904, + "variance": 1728.575149940991, + "sd": 41.576136784710904, + "sem": 4.677680846372364, + "df": 78, + "critical": 1.991, + "moe": 9.313262565127378, + "p75": 6.099999904632568, + "p99": 375.59999990463257, + "p995": 375.59999990463257, + "p999": 375.59999990463257, + "sampleCount": 79, + "median": 6 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 2, + "rme": 3.3141448117941117, + "samples": [], + "totalTime": 502.8999996185303, + "min": 5, + "max": 11.299999713897705, + "hz": 171.00815284397382, + "period": 5.8476744141689565, + "mean": 5.8476744141689565, + "variance": 0.8168768542612354, + "sd": 0.9038123999266857, + "sem": 0.09746059753974967, + "df": 85, + "critical": 1.9885, + "moe": 0.1938003982077922, + "p75": 6.099999904632568, + "p99": 11.299999713897705, + "p995": 11.299999713897705, + "p999": 11.299999713897705, + "sampleCount": 86, + "median": 5.5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 12.13904029470422, + "samples": [], + "totalTime": 504.69999980926514, + "min": 5, + "max": 36.09999990463257, + "hz": 172.37963152938144, + "period": 5.801149423095001, + "mean": 5.801149423095001, + "variance": 10.914300921179375, + "sd": 3.3036799059805078, + "sem": 0.35419166382934497, + "df": 86, + "critical": 1.9882, + "moe": 0.7042038660255037, + "p75": 5.699999809265137, + "p99": 36.09999990463257, + "p995": 36.09999990463257, + "p999": 36.09999990463257, + "sampleCount": 87, + "median": 5.400000095367432 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 1.1952946117007262, + "samples": [], + "totalTime": 500.5, + "min": 10, + "max": 11.5, + "hz": 93.90609390609391, + "period": 10.648936170212766, + "mean": 10.648936170212766, + "variance": 0.1877705836230266, + "sd": 0.43332503230603536, + "sem": 0.06320695215314473, + "df": 46, + "critical": 2.0138, + "moe": 0.12728616024600284, + "p75": 11, + "p99": 11.5, + "p995": 11.5, + "p999": 11.5, + "sampleCount": 47, + "median": 10.599999904632568 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 12.620363832843942, + "samples": [], + "totalTime": 504.19999980926514, + "min": 8.699999809265137, + "max": 40.89999961853027, + "hz": 99.16699726083816, + "period": 10.083999996185304, + "mean": 10.083999996185304, + "variance": 20.04014647349146, + "sd": 4.476622216972464, + "sem": 0.633089985286317, + "df": 49, + "critical": 2.0102, + "moe": 1.2726374884225546, + "p75": 9.800000190734863, + "p99": 40.89999961853027, + "p995": 40.89999961853027, + "p999": 40.89999961853027, + "sampleCount": 50, + "median": 9.349999904632568 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 2.7044948120670775, + "samples": [], + "totalTime": 511.59999990463257, + "min": 26, + "max": 31.59999990463257, + "hz": 35.18373730132014, + "period": 28.42222221692403, + "mean": 28.42222221692403, + "variance": 2.3888889474806687, + "sd": 1.5456031015369596, + "sem": 0.3643021447065814, + "df": 17, + "critical": 2.11, + "moe": 0.7686775253308867, + "p75": 29.300000190734863, + "p99": 31.59999990463257, + "p995": 31.59999990463257, + "p999": 31.59999990463257, + "sampleCount": 18, + "median": 28.149999856948853 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 69.54688531635222, + "samples": [], + "totalTime": 528.4000000953674, + "min": 31, + "max": 197.90000009536743, + "hz": 20.817562448930133, + "period": 48.036363645033404, + "mean": 48.036363645033404, + "variance": 2473.192548393076, + "sd": 49.73120296547305, + "sem": 14.994521873589445, + "df": 10, + "critical": 2.228, + "moe": 33.40779473435729, + "p75": 35, + "p99": 197.90000009536743, + "p995": 197.90000009536743, + "p999": 197.90000009536743, + "sampleCount": 11, + "median": 32.80000019073486 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 6.758289145562733, + "samples": [], + "totalTime": 533.4999995231628, + "min": 45.59999990463257, + "max": 59.59999990463257, + "hz": 18.744142472235996, + "period": 53.34999995231628, + "mean": 53.34999995231628, + "variance": 25.40722202830847, + "sd": 5.040557710046426, + "sem": 1.5939643041269296, + "df": 9, + "critical": 2.262, + "moe": 3.605547255935115, + "p75": 57.69999980926514, + "p99": 59.59999990463257, + "p995": 59.59999990463257, + "p999": 59.59999990463257, + "sampleCount": 10, + "median": 53.89999985694885 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 0.7296575043215849, + "samples": [], + "totalTime": 504.3999991416931, + "min": 4.5, + "max": 5.300000190734863, + "hz": 204.2030138288439, + "period": 4.8970873703077, + "mean": 4.8970873703077, + "variance": 0.03342280054377501, + "sd": 0.1828190376951345, + "sem": 0.018013695044683756, + "df": 102, + "critical": 1.9836, + "moe": 0.0357319654906347, + "p75": 5, + "p99": 5.299999713897705, + "p995": 5.300000190734863, + "p999": 5.300000190734863, + "sampleCount": 103, + "median": 4.900000095367432 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.2908032091650044, + "samples": [], + "totalTime": 504.09999990463257, + "min": 5.599999904632568, + "max": 7, + "hz": 162.66613770187075, + "period": 6.147560974446739, + "mean": 6.147560974446739, + "variance": 0.13042607212099921, + "sd": 0.3611454999318131, + "sem": 0.03988184869253351, + "df": 81, + "critical": 1.9897, + "moe": 0.07935291434353392, + "p75": 6.400000095367432, + "p99": 7, + "p995": 7, + "p999": 7, + "sampleCount": 82, + "median": 6.199999809265137 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.325351626003884, + "samples": [], + "totalTime": 502.69999980926514, + "min": 0.09999990463256836, + "max": 5.299999713897705, + "hz": 220.80763883452502, + "period": 4.528828827110496, + "mean": 4.528828827110496, + "variance": 1.0842522417751561, + "sd": 1.0412743355020118, + "sem": 0.09883338613136047, + "df": 110, + "critical": 1.982, + "moe": 0.19588777131235646, + "p75": 4.800000190734863, + "p99": 5.199999809265137, + "p995": 5.299999713897705, + "p999": 5.299999713897705, + "sampleCount": 111, + "median": 4.799999713897705 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.9973134740107412, + "samples": [], + "totalTime": 504.19999980926514, + "min": 4, + "max": 6.599999904632568, + "hz": 212.21737413819366, + "period": 4.712149530927712, + "mean": 4.712149530927712, + "variance": 0.24107742708969823, + "sd": 0.49099636158499, + "sem": 0.04746640987328683, + "df": 106, + "critical": 1.9828, + "moe": 0.09411639749675313, + "p75": 5.099999904632568, + "p99": 5.800000190734863, + "p995": 6.599999904632568, + "p999": 6.599999904632568, + "sampleCount": 107, + "median": 4.800000190734863 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 3.6979598412671537, + "samples": [], + "totalTime": 504.59999990463257, + "min": 13.200000286102295, + "max": 20.59999990463257, + "hz": 69.36187080185267, + "period": 14.417142854418074, + "mean": 14.417142854418074, + "variance": 2.4055797680766973, + "sd": 1.550993155393246, + "sem": 0.2621656928670818, + "df": 34, + "critical": 2.0336, + "moe": 0.5331401530144975, + "p75": 14.5, + "p99": 20.59999990463257, + "p995": 20.59999990463257, + "p999": 20.59999990463257, + "sampleCount": 35, + "median": 14.099999904632568 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 24.824544910708322, + "samples": [], + "totalTime": 506, + "min": 0.8999996185302734, + "max": 67.40000009536743, + "hz": 173.91304347826087, + "period": 5.75, + "mean": 5.75, + "variance": 45.37241392354859, + "sd": 6.735904833320361, + "sem": 0.7180498678835597, + "df": 87, + "critical": 1.9879, + "moe": 1.4274113323657285, + "p75": 5.400000095367432, + "p99": 67.40000009536743, + "p995": 67.40000009536743, + "p999": 67.40000009536743, + "sampleCount": 88, + "median": 5.100000381469727 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 3.8957060586334817, + "samples": [], + "totalTime": 504.90000009536743, + "min": 4.799999713897705, + "max": 11.5, + "hz": 166.3695781028595, + "period": 6.010714286849613, + "mean": 6.010714286849613, + "variance": 1.1641007854196135, + "sd": 1.0789350237246047, + "sem": 0.11772146228945182, + "df": 83, + "critical": 1.9891, + "moe": 0.23415976063994864, + "p75": 6.100000381469727, + "p99": 11.5, + "p995": 11.5, + "p999": 11.5, + "sampleCount": 84, + "median": 5.799999713897705 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 2.411517484613001, + "samples": [], + "totalTime": 535.6000003814697, + "min": 50.90000009536743, + "max": 57.69999980926514, + "hz": 18.67064972531313, + "period": 53.560000038146974, + "mean": 53.560000038146974, + "variance": 3.2604441574944656, + "sd": 1.805670002379855, + "sem": 0.5710029910162, + "df": 9, + "critical": 2.262, + "moe": 1.2916087656786444, + "p75": 54, + "p99": 57.69999980926514, + "p995": 57.69999980926514, + "p999": 57.69999980926514, + "sampleCount": 10, + "median": 53.5 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 18.355520108924388, + "samples": [], + "totalTime": 504.2999997138977, + "min": 4.399999618530273, + "max": 53.5, + "hz": 105.09617297257238, + "period": 9.515094334224486, + "mean": 9.515094334224486, + "variance": 40.12861394807463, + "sd": 6.334714985543914, + "sem": 0.8701400228685235, + "df": 52, + "critical": 2.0072, + "moe": 1.7465450539017005, + "p75": 9.299999713897705, + "p99": 53.5, + "p995": 53.5, + "p999": 53.5, + "sampleCount": 53, + "median": 8.700000286102295 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 11.319492697158209, + "samples": [], + "totalTime": 532.8000001907349, + "min": 29.40000009536743, + "max": 61.19999980926514, + "hz": 28.153153143074725, + "period": 35.520000012715656, + "mean": 35.520000012715656, + "variance": 52.70314205959869, + "sd": 7.259692972819077, + "sem": 1.8744446654871532, + "df": 14, + "critical": 2.145, + "moe": 4.020683807469943, + "p75": 34.80000019073486, + "p99": 61.19999980926514, + "p995": 61.19999980926514, + "p999": 61.19999980926514, + "sampleCount": 15, + "median": 33.80000019073486 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 3.7873526539442204, + "samples": [], + "totalTime": 2230.9000000953674, + "min": 210.30000019073486, + "max": 246.09999990463257, + "hz": 4.4824958534997155, + "period": 223.09000000953674, + "mean": 223.09000000953674, + "variance": 139.52322213766314, + "sd": 11.811994841586376, + "sem": 3.735280740957273, + "df": 9, + "critical": 2.262, + "moe": 8.44920503604535, + "p75": 230.7000002861023, + "p99": 246.09999990463257, + "p995": 246.09999990463257, + "p999": 246.09999990463257, + "sampleCount": 10, + "median": 220.45000004768372 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 80.9927950512362, + "samples": [], + "totalTime": 729.7000002861023, + "min": 39.19999980926514, + "max": 306.1000003814697, + "hz": 13.704262020116731, + "period": 72.97000002861023, + "mean": 72.97000002861023, + "variance": 6826.471242113537, + "sd": 82.62246209181579, + "sem": 26.127516610105783, + "df": 9, + "critical": 2.262, + "moe": 59.10044257205928, + "p75": 64.90000009536743, + "p99": 306.1000003814697, + "p995": 306.1000003814697, + "p999": 306.1000003814697, + "sampleCount": 10, + "median": 42.049999952316284 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/dm-idb.json b/bench-results/dm-idb.json new file mode 100644 index 000000000..2940e6b80 --- /dev/null +++ b/bench-results/dm-idb.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 54.50622258173367, + "samples": [], + "totalTime": 501.90000009536743, + "min": 0, + "max": 139.59999990463257, + "hz": 5437.338114129219, + "period": 0.18391352147136952, + "mean": 0.18391352147136952, + "variance": 7.138564433903858, + "sd": 2.6718092061193026, + "sem": 0.051145057842392455, + "df": 2728, + "critical": 1.96, + "moe": 0.10024431337108922, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.40000009536743164, + "sampleCount": 2729, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 13.249307690921338, + "samples": [], + "totalTime": 500.00000047683716, + "min": 0, + "max": 33.69999980926514, + "hz": 7207.999993125915, + "period": 0.1387347393109981, + "mean": 0.1387347393109981, + "variance": 0.3169782448203781, + "sd": 0.5630082102601863, + "sem": 0.009378261472199868, + "df": 3603, + "critical": 1.96, + "moe": 0.018381392485511742, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.3000001907348633, + "sampleCount": 3604, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 49.94193862437275, + "samples": [], + "totalTime": 500.09999990463257, + "min": 0, + "max": 127.5, + "hz": 5740.851830728835, + "period": 0.174190177605236, + "mean": 0.174190177605236, + "variance": 5.6558667214879685, + "sd": 2.378206618754554, + "sem": 0.044384669178210635, + "df": 2870, + "critical": 1.96, + "moe": 0.08699395158929285, + "p75": 0.19999980926513672, + "p99": 0.20000028610229492, + "p995": 0.3000001907348633, + "p999": 0.40000009536743164, + "sampleCount": 2871, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 225.64307967783276, + "samples": [], + "totalTime": 631.8000001907349, + "min": 0.09999990463256836, + "max": 630.4000000953674, + "hz": 15.827793600793111, + "period": 63.18000001907349, + "mean": 63.18000001907349, + "variance": 39720.80845513915, + "sd": 199.30079893251596, + "sem": 63.02444641180052, + "df": 9, + "critical": 2.262, + "moe": 142.56129778349276, + "p75": 0.20000028610229492, + "p99": 630.4000000953674, + "p995": 630.4000000953674, + "p999": 630.4000000953674, + "sampleCount": 10, + "median": 0.19999980926513672 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 9.579448003266005, + "samples": [], + "totalTime": 500.0000023841858, + "min": 0, + "max": 20.800000190734863, + "hz": 15473.99992621422, + "period": 0.0646245317803006, + "mean": 0.0646245317803006, + "variance": 0.07718559247145353, + "sd": 0.27782295166428117, + "sem": 0.003158506846555108, + "df": 7736, + "critical": 1.96, + "moe": 0.006190673419248011, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 0.40000009536743164, + "sampleCount": 7737, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 0.6199738249330471, + "samples": [], + "totalTime": 503.09999990463257, + "min": 4, + "max": 4.800000190734863, + "hz": 218.6444047323625, + "period": 4.573636362769387, + "mean": 4.573636362769387, + "variance": 0.022509596704574013, + "sd": 0.15003198560498363, + "sem": 0.014304988546458512, + "df": 109, + "critical": 1.9822, + "moe": 0.02835534829679006, + "p75": 4.600000381469727, + "p99": 4.800000190734863, + "p995": 4.800000190734863, + "p999": 4.800000190734863, + "sampleCount": 110, + "median": 4.599999904632568 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 2.3397265581246294, + "samples": [], + "totalTime": 1133.7000002861023, + "min": 109.2000002861023, + "max": 119.80000019073486, + "hz": 8.820675661529844, + "period": 113.37000002861024, + "mean": 113.37000002861024, + "variance": 13.75122226651512, + "sd": 3.708264050268686, + "sem": 1.1726560564170176, + "df": 9, + "critical": 2.262, + "moe": 2.652547999615294, + "p75": 116.09999990463257, + "p99": 119.80000019073486, + "p995": 119.80000019073486, + "p999": 119.80000019073486, + "sampleCount": 10, + "median": 112.04999995231628 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 9.45685950813143, + "samples": [], + "totalTime": 500.00000190734863, + "min": 0.10000038146972656, + "max": 20.899999618530273, + "hz": 2823.999989227295, + "period": 0.35410765007602596, + "mean": 0.35410765007602596, + "variance": 0.412180125271523, + "sd": 0.6420125584998497, + "sem": 0.017085440293487467, + "df": 1411, + "critical": 1.96, + "moe": 0.03348746297523544, + "p75": 0.3000001907348633, + "p99": 1.0999999046325684, + "p995": 1.3999996185302734, + "p999": 9.799999713897705, + "sampleCount": 1412, + "median": 0.3000001907348633 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 1.9133023415925396, + "samples": [], + "totalTime": 500.19999980926514, + "min": 4, + "max": 8.5, + "hz": 221.91123559041625, + "period": 4.506306304587974, + "mean": 4.506306304587974, + "variance": 0.21005078136719008, + "sd": 0.4583129731604704, + "sem": 0.0435011423032361, + "df": 110, + "critical": 1.982, + "moe": 0.08621926404501395, + "p75": 4.599999904632568, + "p99": 5, + "p995": 8.5, + "p999": 8.5, + "sampleCount": 111, + "median": 4.599999904632568 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.0074849892867523, + "samples": [], + "totalTime": 1176.6999998092651, + "min": 115.80000019073486, + "max": 120.2999997138977, + "hz": 8.498342824527008, + "period": 117.66999998092652, + "mean": 117.66999998092652, + "variance": 2.7467774543762564, + "sd": 1.6573404762981734, + "sem": 0.5240970763490534, + "df": 9, + "critical": 2.262, + "moe": 1.185507586701559, + "p75": 119.09999990463257, + "p99": 120.2999997138977, + "p995": 120.2999997138977, + "p999": 120.2999997138977, + "sampleCount": 10, + "median": 117.25 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 9.169789243545004, + "samples": [], + "totalTime": 518.5999984741211, + "min": 1.0999999046325684, + "max": 20.90000009536743, + "hz": 659.467799857825, + "period": 1.5163742645442138, + "mean": 1.5163742645442138, + "variance": 1.7212560574977103, + "sd": 1.3119664848987989, + "sem": 0.07094302255207142, + "df": 341, + "critical": 1.96, + "moe": 0.13904832420205998, + "p75": 1.4000000953674316, + "p99": 5.700000286102295, + "p995": 11.300000190734863, + "p999": 20.90000009536743, + "sampleCount": 342, + "median": 1.2999999523162842 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 10.732844424147734, + "samples": [], + "totalTime": 503.40000009536743, + "min": 3.8999996185302734, + "max": 31.300000190734863, + "hz": 218.51410405077647, + "period": 4.576363637230613, + "mean": 4.576363637230613, + "variance": 6.754115174698401, + "sd": 2.5988680564234885, + "sem": 0.24779234661851995, + "df": 109, + "critical": 1.9822, + "moe": 0.49117398946723023, + "p75": 4.699999809265137, + "p99": 5.199999809265137, + "p995": 31.300000190734863, + "p999": 31.300000190734863, + "sampleCount": 110, + "median": 4.150000095367432 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 2.078810225257847, + "samples": [], + "totalTime": 1210.3999996185303, + "min": 118.09999990463257, + "max": 128.90000009536743, + "hz": 8.261731661559486, + "period": 121.03999996185303, + "mean": 121.03999996185303, + "variance": 12.373777923160155, + "sd": 3.5176381171405557, + "sem": 1.112374843439034, + "df": 9, + "critical": 2.262, + "moe": 2.5161918958590945, + "p75": 123.30000019073486, + "p99": 128.90000009536743, + "p995": 128.90000009536743, + "p999": 128.90000009536743, + "sampleCount": 10, + "median": 119.65000009536743 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 6.488207703160261, + "samples": [], + "totalTime": 502.1999988555908, + "min": 6.5, + "max": 22.09999990463257, + "hz": 121.46555184987314, + "period": 8.232786866485096, + "mean": 8.232786866485096, + "variance": 4.351240387864485, + "sd": 2.08596270049694, + "sem": 0.26708015582802613, + "df": 60, + "critical": 2, + "moe": 0.5341603116560523, + "p75": 8.5, + "p99": 22.09999990463257, + "p995": 22.09999990463257, + "p999": 22.09999990463257, + "sampleCount": 61, + "median": 7.699999809265137 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 1.3781958879879457, + "samples": [], + "totalTime": 504, + "min": 4, + "max": 5.200000286102295, + "hz": 228.1746031746032, + "period": 4.3826086956521735, + "mean": 4.3826086956521735, + "variance": 0.10688788741352917, + "sd": 0.3269371306742768, + "sem": 0.03048704463460549, + "df": 114, + "critical": 1.9812, + "moe": 0.0604009328300804, + "p75": 4.599999904632568, + "p99": 5.200000286102295, + "p995": 5.200000286102295, + "p999": 5.200000286102295, + "sampleCount": 115, + "median": 4.299999713897705 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 2.488276067909993, + "samples": [], + "totalTime": 1215.9000000953674, + "min": 115.59999990463257, + "max": 129.09999990463257, + "hz": 8.224360555321708, + "period": 121.59000000953674, + "mean": 121.59000000953674, + "variance": 17.889888793733412, + "sd": 4.229644050476756, + "sem": 1.3375308891286741, + "df": 9, + "critical": 2.262, + "moe": 3.025494871209061, + "p75": 122.7000002861023, + "p99": 129.09999990463257, + "p995": 129.09999990463257, + "p999": 129.09999990463257, + "sampleCount": 10, + "median": 120.54999995231628 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 106.67520880993533, + "samples": [], + "totalTime": 502.8999996185303, + "min": 3.299999713897705, + "max": 272.1000003814697, + "hz": 129.25034807974765, + "period": 7.736923071054312, + "mean": 7.736923071054312, + "variance": 1109.1389311227797, + "sd": 33.303737494803485, + "sem": 4.130820240996621, + "df": 64, + "critical": 1.998, + "moe": 8.253378841511248, + "p75": 3.6000003814697266, + "p99": 272.1000003814697, + "p995": 272.1000003814697, + "p999": 272.1000003814697, + "sampleCount": 65, + "median": 3.5 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 3.0317992326491705, + "samples": [], + "totalTime": 515.7000002861023, + "min": 20.5, + "max": 26.90000009536743, + "hz": 44.599573370641764, + "period": 22.421739142874014, + "mean": 22.421739142874014, + "variance": 2.470869454545972, + "sd": 1.5718999505521882, + "sem": 0.32776379714573434, + "df": 22, + "critical": 2.074, + "moe": 0.679782115280253, + "p75": 22.800000190734863, + "p99": 26.90000009536743, + "p995": 26.90000009536743, + "p999": 26.90000009536743, + "sampleCount": 23, + "median": 22.199999809265137 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 5.101646977386887, + "samples": [], + "totalTime": 899.9999995231628, + "min": 86.30000019073486, + "max": 107.39999961853027, + "hz": 11.11111111699799, + "period": 89.99999995231629, + "mean": 89.99999995231629, + "variance": 41.20222063912289, + "sd": 6.418895593411914, + "sem": 2.029833013799975, + "df": 9, + "critical": 2.262, + "moe": 4.591482277215543, + "p75": 90.09999990463257, + "p99": 107.39999961853027, + "p995": 107.39999961853027, + "p999": 107.39999961853027, + "sampleCount": 10, + "median": 87.45000004768372 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 14.883070638564389, + "samples": [], + "totalTime": 4130.39999961853, + "min": 373.40000009536743, + "max": 655.8999996185303, + "hz": 2.4210730197858723, + "period": 413.039999961853, + "mean": 413.039999961853, + "variance": 7385.571533166674, + "sd": 85.93934799128205, + "sem": 27.17640802822675, + "df": 9, + "critical": 2.262, + "moe": 61.47303495984891, + "p75": 393.2999997138977, + "p99": 655.8999996185303, + "p995": 655.8999996185303, + "p999": 655.8999996185303, + "sampleCount": 10, + "median": 384 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.32406339987359434, + "samples": [], + "totalTime": 504.5999994277954, + "min": 4.5, + "max": 5, + "hz": 210.0673803412634, + "period": 4.76037735309241, + "mean": 4.76037735309241, + "variance": 0.00641509608764699, + "sd": 0.08009429497565347, + "sem": 0.007779445636532467, + "df": 105, + "critical": 1.983, + "moe": 0.015426640697243883, + "p75": 4.800000190734863, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 106, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.4198453715860097, + "samples": [], + "totalTime": 502.6000003814697, + "min": 4.5, + "max": 5, + "hz": 208.9136488665057, + "period": 4.786666670299712, + "mean": 4.786666670299712, + "variance": 0.010782051013112564, + "sd": 0.1038366554407092, + "sem": 0.010133419961931981, + "df": 104, + "critical": 1.9832, + "moe": 0.020096598468503507, + "p75": 4.899999618530273, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 105, + "median": 4.800000190734863 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 0.39727582120239235, + "samples": [], + "totalTime": 500, + "min": 4.599999904632568, + "max": 5.099999904632568, + "hz": 202, + "period": 4.9504950495049505, + "mean": 4.9504950495049505, + "variance": 0.009924749804973446, + "sd": 0.09962303852509943, + "sem": 0.009912862833419644, + "df": 100, + "critical": 1.984, + "moe": 0.019667119861504573, + "p75": 5, + "p99": 5.099999904632568, + "p995": 5.099999904632568, + "p999": 5.099999904632568, + "sampleCount": 101, + "median": 5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 0.6761934850014394, + "samples": [], + "totalTime": 500, + "min": 4.399999618530273, + "max": 5.699999809265137, + "hz": 218, + "period": 4.587155963302752, + "mean": 4.587155963302752, + "variance": 0.026685349605080115, + "sd": 0.1633565107520362, + "sem": 0.01564671598603119, + "df": 108, + "critical": 1.9824, + "moe": 0.03101804977070823, + "p75": 4.600000381469727, + "p99": 5.099999904632568, + "p995": 5.699999809265137, + "p999": 5.699999809265137, + "sampleCount": 109, + "median": 4.599999904632568 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 3, + "rme": 86.11279758461367, + "samples": [], + "totalTime": 854.4000000953674, + "min": 5.699999809265137, + "max": 375.59999990463257, + "hz": 92.46254680615881, + "period": 10.815189874624904, + "mean": 10.815189874624904, + "variance": 1728.575149940991, + "sd": 41.576136784710904, + "sem": 4.677680846372364, + "df": 78, + "critical": 1.991, + "moe": 9.313262565127378, + "p75": 6.099999904632568, + "p99": 375.59999990463257, + "p995": 375.59999990463257, + "p999": 375.59999990463257, + "sampleCount": 79, + "median": 6 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 2, + "rme": 3.3141448117941117, + "samples": [], + "totalTime": 502.8999996185303, + "min": 5, + "max": 11.299999713897705, + "hz": 171.00815284397382, + "period": 5.8476744141689565, + "mean": 5.8476744141689565, + "variance": 0.8168768542612354, + "sd": 0.9038123999266857, + "sem": 0.09746059753974967, + "df": 85, + "critical": 1.9885, + "moe": 0.1938003982077922, + "p75": 6.099999904632568, + "p99": 11.299999713897705, + "p995": 11.299999713897705, + "p999": 11.299999713897705, + "sampleCount": 86, + "median": 5.5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 12.13904029470422, + "samples": [], + "totalTime": 504.69999980926514, + "min": 5, + "max": 36.09999990463257, + "hz": 172.37963152938144, + "period": 5.801149423095001, + "mean": 5.801149423095001, + "variance": 10.914300921179375, + "sd": 3.3036799059805078, + "sem": 0.35419166382934497, + "df": 86, + "critical": 1.9882, + "moe": 0.7042038660255037, + "p75": 5.699999809265137, + "p99": 36.09999990463257, + "p995": 36.09999990463257, + "p999": 36.09999990463257, + "sampleCount": 87, + "median": 5.400000095367432 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 1.1952946117007262, + "samples": [], + "totalTime": 500.5, + "min": 10, + "max": 11.5, + "hz": 93.90609390609391, + "period": 10.648936170212766, + "mean": 10.648936170212766, + "variance": 0.1877705836230266, + "sd": 0.43332503230603536, + "sem": 0.06320695215314473, + "df": 46, + "critical": 2.0138, + "moe": 0.12728616024600284, + "p75": 11, + "p99": 11.5, + "p995": 11.5, + "p999": 11.5, + "sampleCount": 47, + "median": 10.599999904632568 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 12.620363832843942, + "samples": [], + "totalTime": 504.19999980926514, + "min": 8.699999809265137, + "max": 40.89999961853027, + "hz": 99.16699726083816, + "period": 10.083999996185304, + "mean": 10.083999996185304, + "variance": 20.04014647349146, + "sd": 4.476622216972464, + "sem": 0.633089985286317, + "df": 49, + "critical": 2.0102, + "moe": 1.2726374884225546, + "p75": 9.800000190734863, + "p99": 40.89999961853027, + "p995": 40.89999961853027, + "p999": 40.89999961853027, + "sampleCount": 50, + "median": 9.349999904632568 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 2.7044948120670775, + "samples": [], + "totalTime": 511.59999990463257, + "min": 26, + "max": 31.59999990463257, + "hz": 35.18373730132014, + "period": 28.42222221692403, + "mean": 28.42222221692403, + "variance": 2.3888889474806687, + "sd": 1.5456031015369596, + "sem": 0.3643021447065814, + "df": 17, + "critical": 2.11, + "moe": 0.7686775253308867, + "p75": 29.300000190734863, + "p99": 31.59999990463257, + "p995": 31.59999990463257, + "p999": 31.59999990463257, + "sampleCount": 18, + "median": 28.149999856948853 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 69.54688531635222, + "samples": [], + "totalTime": 528.4000000953674, + "min": 31, + "max": 197.90000009536743, + "hz": 20.817562448930133, + "period": 48.036363645033404, + "mean": 48.036363645033404, + "variance": 2473.192548393076, + "sd": 49.73120296547305, + "sem": 14.994521873589445, + "df": 10, + "critical": 2.228, + "moe": 33.40779473435729, + "p75": 35, + "p99": 197.90000009536743, + "p995": 197.90000009536743, + "p999": 197.90000009536743, + "sampleCount": 11, + "median": 32.80000019073486 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 6.758289145562733, + "samples": [], + "totalTime": 533.4999995231628, + "min": 45.59999990463257, + "max": 59.59999990463257, + "hz": 18.744142472235996, + "period": 53.34999995231628, + "mean": 53.34999995231628, + "variance": 25.40722202830847, + "sd": 5.040557710046426, + "sem": 1.5939643041269296, + "df": 9, + "critical": 2.262, + "moe": 3.605547255935115, + "p75": 57.69999980926514, + "p99": 59.59999990463257, + "p995": 59.59999990463257, + "p999": 59.59999990463257, + "sampleCount": 10, + "median": 53.89999985694885 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 0.7296575043215849, + "samples": [], + "totalTime": 504.3999991416931, + "min": 4.5, + "max": 5.300000190734863, + "hz": 204.2030138288439, + "period": 4.8970873703077, + "mean": 4.8970873703077, + "variance": 0.03342280054377501, + "sd": 0.1828190376951345, + "sem": 0.018013695044683756, + "df": 102, + "critical": 1.9836, + "moe": 0.0357319654906347, + "p75": 5, + "p99": 5.299999713897705, + "p995": 5.300000190734863, + "p999": 5.300000190734863, + "sampleCount": 103, + "median": 4.900000095367432 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.2908032091650044, + "samples": [], + "totalTime": 504.09999990463257, + "min": 5.599999904632568, + "max": 7, + "hz": 162.66613770187075, + "period": 6.147560974446739, + "mean": 6.147560974446739, + "variance": 0.13042607212099921, + "sd": 0.3611454999318131, + "sem": 0.03988184869253351, + "df": 81, + "critical": 1.9897, + "moe": 0.07935291434353392, + "p75": 6.400000095367432, + "p99": 7, + "p995": 7, + "p999": 7, + "sampleCount": 82, + "median": 6.199999809265137 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.325351626003884, + "samples": [], + "totalTime": 502.69999980926514, + "min": 0.09999990463256836, + "max": 5.299999713897705, + "hz": 220.80763883452502, + "period": 4.528828827110496, + "mean": 4.528828827110496, + "variance": 1.0842522417751561, + "sd": 1.0412743355020118, + "sem": 0.09883338613136047, + "df": 110, + "critical": 1.982, + "moe": 0.19588777131235646, + "p75": 4.800000190734863, + "p99": 5.199999809265137, + "p995": 5.299999713897705, + "p999": 5.299999713897705, + "sampleCount": 111, + "median": 4.799999713897705 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.9973134740107412, + "samples": [], + "totalTime": 504.19999980926514, + "min": 4, + "max": 6.599999904632568, + "hz": 212.21737413819366, + "period": 4.712149530927712, + "mean": 4.712149530927712, + "variance": 0.24107742708969823, + "sd": 0.49099636158499, + "sem": 0.04746640987328683, + "df": 106, + "critical": 1.9828, + "moe": 0.09411639749675313, + "p75": 5.099999904632568, + "p99": 5.800000190734863, + "p995": 6.599999904632568, + "p999": 6.599999904632568, + "sampleCount": 107, + "median": 4.800000190734863 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 3.6979598412671537, + "samples": [], + "totalTime": 504.59999990463257, + "min": 13.200000286102295, + "max": 20.59999990463257, + "hz": 69.36187080185267, + "period": 14.417142854418074, + "mean": 14.417142854418074, + "variance": 2.4055797680766973, + "sd": 1.550993155393246, + "sem": 0.2621656928670818, + "df": 34, + "critical": 2.0336, + "moe": 0.5331401530144975, + "p75": 14.5, + "p99": 20.59999990463257, + "p995": 20.59999990463257, + "p999": 20.59999990463257, + "sampleCount": 35, + "median": 14.099999904632568 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 24.824544910708322, + "samples": [], + "totalTime": 506, + "min": 0.8999996185302734, + "max": 67.40000009536743, + "hz": 173.91304347826087, + "period": 5.75, + "mean": 5.75, + "variance": 45.37241392354859, + "sd": 6.735904833320361, + "sem": 0.7180498678835597, + "df": 87, + "critical": 1.9879, + "moe": 1.4274113323657285, + "p75": 5.400000095367432, + "p99": 67.40000009536743, + "p995": 67.40000009536743, + "p999": 67.40000009536743, + "sampleCount": 88, + "median": 5.100000381469727 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 3.8957060586334817, + "samples": [], + "totalTime": 504.90000009536743, + "min": 4.799999713897705, + "max": 11.5, + "hz": 166.3695781028595, + "period": 6.010714286849613, + "mean": 6.010714286849613, + "variance": 1.1641007854196135, + "sd": 1.0789350237246047, + "sem": 0.11772146228945182, + "df": 83, + "critical": 1.9891, + "moe": 0.23415976063994864, + "p75": 6.100000381469727, + "p99": 11.5, + "p995": 11.5, + "p999": 11.5, + "sampleCount": 84, + "median": 5.799999713897705 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 2.411517484613001, + "samples": [], + "totalTime": 535.6000003814697, + "min": 50.90000009536743, + "max": 57.69999980926514, + "hz": 18.67064972531313, + "period": 53.560000038146974, + "mean": 53.560000038146974, + "variance": 3.2604441574944656, + "sd": 1.805670002379855, + "sem": 0.5710029910162, + "df": 9, + "critical": 2.262, + "moe": 1.2916087656786444, + "p75": 54, + "p99": 57.69999980926514, + "p995": 57.69999980926514, + "p999": 57.69999980926514, + "sampleCount": 10, + "median": 53.5 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 18.355520108924388, + "samples": [], + "totalTime": 504.2999997138977, + "min": 4.399999618530273, + "max": 53.5, + "hz": 105.09617297257238, + "period": 9.515094334224486, + "mean": 9.515094334224486, + "variance": 40.12861394807463, + "sd": 6.334714985543914, + "sem": 0.8701400228685235, + "df": 52, + "critical": 2.0072, + "moe": 1.7465450539017005, + "p75": 9.299999713897705, + "p99": 53.5, + "p995": 53.5, + "p999": 53.5, + "sampleCount": 53, + "median": 8.700000286102295 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 11.319492697158209, + "samples": [], + "totalTime": 532.8000001907349, + "min": 29.40000009536743, + "max": 61.19999980926514, + "hz": 28.153153143074725, + "period": 35.520000012715656, + "mean": 35.520000012715656, + "variance": 52.70314205959869, + "sd": 7.259692972819077, + "sem": 1.8744446654871532, + "df": 14, + "critical": 2.145, + "moe": 4.020683807469943, + "p75": 34.80000019073486, + "p99": 61.19999980926514, + "p995": 61.19999980926514, + "p999": 61.19999980926514, + "sampleCount": 15, + "median": 33.80000019073486 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 3.7873526539442204, + "samples": [], + "totalTime": 2230.9000000953674, + "min": 210.30000019073486, + "max": 246.09999990463257, + "hz": 4.4824958534997155, + "period": 223.09000000953674, + "mean": 223.09000000953674, + "variance": 139.52322213766314, + "sd": 11.811994841586376, + "sem": 3.735280740957273, + "df": 9, + "critical": 2.262, + "moe": 8.44920503604535, + "p75": 230.7000002861023, + "p99": 246.09999990463257, + "p995": 246.09999990463257, + "p999": 246.09999990463257, + "sampleCount": 10, + "median": 220.45000004768372 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 80.9927950512362, + "samples": [], + "totalTime": 729.7000002861023, + "min": 39.19999980926514, + "max": 306.1000003814697, + "hz": 13.704262020116731, + "period": 72.97000002861023, + "mean": 72.97000002861023, + "variance": 6826.471242113537, + "sd": 82.62246209181579, + "sem": 26.127516610105783, + "df": 9, + "critical": 2.262, + "moe": 59.10044257205928, + "p75": 64.90000009536743, + "p99": 306.1000003814697, + "p995": 306.1000003814697, + "p999": 306.1000003814697, + "sampleCount": 10, + "median": 42.049999952316284 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/dm-sqlite-new.json b/bench-results/dm-sqlite-new.json new file mode 100644 index 000000000..8c88a57a0 --- /dev/null +++ b/bench-results/dm-sqlite-new.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 55.38147488620398, + "samples": [], + "totalTime": 500.09999990463257, + "min": 0, + "max": 140.69999980926514, + "hz": 5284.943012405542, + "period": 0.18921679905585795, + "mean": 0.18921679905585795, + "variance": 7.554982069535371, + "sd": 2.748632763672763, + "sem": 0.053464823494693385, + "df": 2642, + "critical": 1.96, + "moe": 0.10479105404959903, + "p75": 0.19999980926513672, + "p99": 0.20000028610229492, + "p995": 0.3000001907348633, + "p999": 10.100000381469727, + "sampleCount": 2643, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 13.847680319614597, + "samples": [], + "totalTime": 500.1000008583069, + "min": 0, + "max": 34.80000019073486, + "hz": 7196.560675511183, + "period": 0.13895526558997134, + "mean": 0.13895526558997134, + "variance": 0.3468756221343432, + "sd": 0.5889614776318933, + "sem": 0.009817388248046253, + "df": 3598, + "critical": 1.96, + "moe": 0.019242080966170656, + "p75": 0.19999980926513672, + "p99": 0.20000028610229492, + "p995": 0.2999997138977051, + "p999": 1.700000286102295, + "sampleCount": 3599, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 56.7246382917377, + "samples": [], + "totalTime": 500.00000047683716, + "min": 0, + "max": 144.7999997138977, + "hz": 5567.999994689942, + "period": 0.179597701320703, + "mean": 0.179597701320703, + "variance": 7.521459240545109, + "sd": 2.7425278923914536, + "sem": 0.051977625742063355, + "df": 2783, + "critical": 1.96, + "moe": 0.10187614645444418, + "p75": 0.19999980926513672, + "p99": 0.20000028610229492, + "p995": 0.3000001907348633, + "p999": 0.39999961853027344, + "sampleCount": 2784, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 225.72092498822457, + "samples": [], + "totalTime": 682, + "min": 0.09999990463256836, + "max": 680.7000002861023, + "hz": 14.662756598240469, + "period": 68.2, + "mean": 68.2, + "variance": 46315.588932153914, + "sd": 215.2105688207573, + "sem": 68.05555740140103, + "df": 9, + "critical": 2.262, + "moe": 153.94167084196914, + "p75": 0.19999980926513672, + "p99": 680.7000002861023, + "p995": 680.7000002861023, + "p999": 680.7000002861023, + "sampleCount": 10, + "median": 0.15000009536743164 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 43.24850476435494, + "samples": [], + "totalTime": 500.0000009536743, + "min": 0, + "max": 104.2999997138977, + "hz": 9571.99998174286, + "period": 0.10447137504255627, + "mean": 0.10447137504255627, + "variance": 2.5432986903608787, + "sd": 1.5947723004745469, + "sem": 0.023052197761564832, + "df": 4785, + "critical": 1.96, + "moe": 0.04518230761266707, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 10.100000381469727, + "sampleCount": 4786, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 14.222449016655741, + "samples": [], + "totalTime": 504.30000019073486, + "min": 4, + "max": 40.59999990463257, + "hz": 206.22645243042916, + "period": 4.849038463372451, + "mean": 4.849038463372451, + "variance": 12.573979582145576, + "sd": 3.545980764491761, + "sem": 0.3477120214032337, + "df": 103, + "critical": 1.9834, + "moe": 0.6896520232511738, + "p75": 4.599999904632568, + "p99": 5.199999809265137, + "p995": 40.59999990463257, + "p999": 40.59999990463257, + "sampleCount": 104, + "median": 4.5 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 0.7396513271370015, + "samples": [], + "totalTime": 1106.5999999046326, + "min": 108.5, + "max": 112, + "hz": 9.03668895794488, + "period": 110.65999999046326, + "mean": 110.65999999046326, + "variance": 1.3093332964579352, + "sd": 1.1442610263650228, + "sem": 0.3618471081075452, + "df": 9, + "critical": 2.262, + "moe": 0.8184981585392673, + "p75": 111.5, + "p99": 112, + "p995": 112, + "p999": 112, + "sampleCount": 10, + "median": 110.90000009536743 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 10.660419860572027, + "samples": [], + "totalTime": 500.20000076293945, + "min": 0.19999980926513672, + "max": 24, + "hz": 2385.045977969521, + "period": 0.41927912888762736, + "mean": 0.41927912888762736, + "variance": 0.6204165996897295, + "sd": 0.7876652840450248, + "sem": 0.022804548738352047, + "df": 1192, + "critical": 1.96, + "moe": 0.04469691552717001, + "p75": 0.40000009536743164, + "p99": 1.3999996185302734, + "p995": 1.700000286102295, + "p999": 12.800000190734863, + "sampleCount": 1193, + "median": 0.40000009536743164 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 2.1097521756323467, + "samples": [], + "totalTime": 501.8999996185303, + "min": 4, + "max": 9.400000095367432, + "hz": 219.1671649404376, + "period": 4.562727269259367, + "mean": 4.562727269259367, + "variance": 0.25942369979340024, + "sd": 0.5093365290192725, + "sem": 0.04856333257560783, + "df": 109, + "critical": 1.9822, + "moe": 0.09626223783136985, + "p75": 4.600000381469727, + "p99": 4.900000095367432, + "p995": 9.400000095367432, + "p999": 9.400000095367432, + "sampleCount": 110, + "median": 4.599999904632568 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.3176882961678955, + "samples": [], + "totalTime": 1144.5, + "min": 109.09999990463257, + "max": 116, + "hz": 8.73743993010048, + "period": 114.45, + "mean": 114.45, + "variance": 4.445000046624105, + "sd": 2.1083168752879877, + "sem": 0.6667083355279206, + "df": 9, + "critical": 2.262, + "moe": 1.5080942549641565, + "p75": 115.80000019073486, + "p99": 116, + "p995": 116, + "p999": 116, + "sampleCount": 10, + "median": 115.19999980926514 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 2.468684900565665, + "samples": [], + "totalTime": 500.6000032424927, + "min": 2.6999998092651367, + "max": 5.400000095367432, + "hz": 289.6524152233403, + "period": 3.4524138154654667, + "mean": 3.4524138154654667, + "variance": 0.2741781695528843, + "sd": 0.5236202531920288, + "sem": 0.043484295187468845, + "df": 144, + "critical": 1.96, + "moe": 0.08522921856743894, + "p75": 3.8000001907348633, + "p99": 4.800000190734863, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 145, + "median": 3.4000000953674316 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 11.809430694214495, + "samples": [], + "totalTime": 503.5, + "min": 3.9000000953674316, + "max": 34.09999990463257, + "hz": 210.52631578947367, + "period": 4.75, + "mean": 4.75, + "variance": 8.482142799014158, + "sd": 2.9124118525741096, + "sem": 0.28287844577669613, + "df": 105, + "critical": 1.983, + "moe": 0.5609479579751885, + "p75": 5, + "p99": 5.200000286102295, + "p995": 34.09999990463257, + "p999": 34.09999990463257, + "sampleCount": 106, + "median": 4.300000190734863 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 4.471454513416558, + "samples": [], + "totalTime": 1220.8000001907349, + "min": 115.30000019073486, + "max": 142.09999990463257, + "hz": 8.191349933189404, + "period": 122.08000001907348, + "mean": 122.08000001907348, + "variance": 58.23733252461755, + "sd": 7.631338842209638, + "sem": 2.4132412337894764, + "df": 9, + "critical": 2.262, + "moe": 5.458751670831796, + "p75": 122.59999990463257, + "p99": 142.09999990463257, + "p995": 142.09999990463257, + "p999": 142.09999990463257, + "sampleCount": 10, + "median": 120.69999980926514 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 2.6461050485020143, + "samples": [], + "totalTime": 531.0000004768372, + "min": 30.899999618530273, + "max": 36.59999990463257, + "hz": 30.1318267149379, + "period": 33.18750002980232, + "mean": 33.18750002980232, + "variance": 2.7171669510206033, + "sd": 1.648383132351397, + "sem": 0.4120957830878493, + "df": 15, + "critical": 2.131, + "moe": 0.8781761137602068, + "p75": 34.30000019073486, + "p99": 36.59999990463257, + "p995": 36.59999990463257, + "p999": 36.59999990463257, + "sampleCount": 16, + "median": 33.049999952316284 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 7.831960767191049, + "samples": [], + "totalTime": 504.69999980926514, + "min": 3.8999996185302734, + "max": 23.90000009536743, + "hz": 210.0257579553383, + "period": 4.761320752917595, + "mean": 4.761320752917595, + "variance": 3.7484897015752674, + "sd": 1.9361016764558796, + "sem": 0.1880508186427794, + "df": 105, + "critical": 1.983, + "moe": 0.37290477336863154, + "p75": 5.099999904632568, + "p99": 5.300000190734863, + "p995": 23.90000009536743, + "p999": 23.90000009536743, + "sampleCount": 106, + "median": 4.700000286102295 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.933086181116515, + "samples": [], + "totalTime": 1160.1999998092651, + "min": 112.40000009536743, + "max": 122.69999980926514, + "hz": 8.619203587005673, + "period": 116.01999998092651, + "mean": 116.01999998092651, + "variance": 9.83066627968684, + "sd": 3.135389334626059, + "sem": 0.9914971648818185, + "df": 9, + "critical": 2.262, + "moe": 2.2427665869626736, + "p75": 117.19999980926514, + "p99": 122.69999980926514, + "p995": 122.69999980926514, + "p999": 122.69999980926514, + "sampleCount": 10, + "median": 116.5 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 32.882292925340835, + "samples": [], + "totalTime": 500.40000009536743, + "min": 3.0999999046325684, + "max": 87.30000019073486, + "hz": 243.80495598870692, + "period": 4.101639345043996, + "mean": 4.101639345043996, + "variance": 57.76793143409751, + "sd": 7.6005217869628865, + "sem": 0.688118910295101, + "df": 121, + "critical": 1.96, + "moe": 1.348713064178398, + "p75": 3.5, + "p99": 5.699999809265137, + "p995": 87.30000019073486, + "p999": 87.30000019073486, + "sampleCount": 122, + "median": 3.3999996185302734 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 5.46550945652747, + "samples": [], + "totalTime": 503.5, + "min": 19.40000009536743, + "max": 32.09999990463257, + "hz": 45.680238331678254, + "period": 21.891304347826086, + "mean": 21.891304347826086, + "variance": 7.654466202023502, + "sd": 2.7666705987564733, + "sem": 0.5768906987886423, + "df": 22, + "critical": 2.074, + "moe": 1.196471309287644, + "p75": 21.5, + "p99": 32.09999990463257, + "p995": 32.09999990463257, + "p999": 32.09999990463257, + "sampleCount": 23, + "median": 21 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 11.626672618757159, + "samples": [], + "totalTime": 945, + "min": 87.69999980926514, + "max": 138, + "hz": 10.582010582010582, + "period": 94.5, + "mean": 94.5, + "variance": 235.9333333333334, + "sd": 15.360121527297022, + "sem": 4.857296916324278, + "df": 9, + "critical": 2.262, + "moe": 10.987205624725515, + "p75": 90.69999980926514, + "p99": 138, + "p995": 138, + "p999": 138, + "sampleCount": 10, + "median": 89.35000014305115 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 14.56321274611983, + "samples": [], + "totalTime": 3918.2000002861023, + "min": 356.5, + "max": 614.0999999046326, + "hz": 2.5521923330278726, + "period": 391.82000002861025, + "mean": 391.82000002861025, + "variance": 6363.592881046296, + "sd": 79.77213097972434, + "sem": 25.226162770120816, + "df": 9, + "critical": 2.262, + "moe": 57.06158018601329, + "p75": 387.19999980926514, + "p99": 614.0999999046326, + "p995": 614.0999999046326, + "p999": 614.0999999046326, + "sampleCount": 10, + "median": 360.0499999523163 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.32268131275033796, + "samples": [], + "totalTime": 503.2000002861023, + "min": 4.5, + "max": 4.900000095367432, + "hz": 210.6518281791177, + "period": 4.747169814019833, + "mean": 4.747169814019833, + "variance": 0.006325248639481632, + "sd": 0.07953143177060018, + "sem": 0.007724775529181531, + "df": 105, + "critical": 1.983, + "moe": 0.015318229874366976, + "p75": 4.800000190734863, + "p99": 4.900000095367432, + "p995": 4.900000095367432, + "p999": 4.900000095367432, + "sampleCount": 106, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.31828233787969423, + "samples": [], + "totalTime": 500.30000019073486, + "min": 4.5, + "max": 5, + "hz": 207.87527475584835, + "period": 4.8105769249109125, + "mean": 4.8105769249109125, + "variance": 0.006197722511966117, + "sd": 0.07872561534828494, + "sem": 0.007719681709240473, + "df": 103, + "critical": 1.9834, + "moe": 0.015311216702107553, + "p75": 4.899999618530273, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 104, + "median": 4.800000190734863 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 0.42608822570043947, + "samples": [], + "totalTime": 501.30000019073486, + "min": 4.299999713897705, + "max": 5.5, + "hz": 203.4709753863774, + "period": 4.914705884222891, + "mean": 4.914705884222891, + "variance": 0.011365761343129431, + "sd": 0.10661032474919786, + "sem": 0.01055599511063636, + "df": 101, + "critical": 1.9838, + "moe": 0.020940983100480412, + "p75": 5, + "p99": 5.100000381469727, + "p995": 5.5, + "p999": 5.5, + "sampleCount": 102, + "median": 4.900000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 0.5675895087767245, + "samples": [], + "totalTime": 501.5, + "min": 4.300000190734863, + "max": 5.599999904632568, + "hz": 221.3359920239282, + "period": 4.518018018018018, + "mean": 4.518018018018018, + "variance": 0.018581480524570343, + "sd": 0.13631390436991503, + "sem": 0.012938343226494637, + "df": 110, + "critical": 1.982, + "moe": 0.02564379627491237, + "p75": 4.599999904632568, + "p99": 4.900000095367432, + "p995": 5.599999904632568, + "p999": 5.599999904632568, + "sampleCount": 111, + "median": 4.5 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 2, + "rme": 0.49905041369006553, + "samples": [], + "totalTime": 505.09999990463257, + "min": 5.5, + "max": 6.5, + "hz": 168.28350824796826, + "period": 5.9423529400545005, + "mean": 5.9423529400545005, + "variance": 0.01889915680820556, + "sd": 0.13747420415556352, + "sem": 0.0149111710228609, + "df": 84, + "critical": 1.9888, + "moe": 0.029655336930265758, + "p75": 6, + "p99": 6.5, + "p995": 6.5, + "p999": 6.5, + "sampleCount": 85, + "median": 5.900000095367432 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 3, + "rme": 1.2606089251609203, + "samples": [], + "totalTime": 503.7000002861023, + "min": 5.399999618530273, + "max": 6.699999809265137, + "hz": 158.82469715020824, + "period": 6.2962500035762785, + "mean": 6.2962500035762785, + "variance": 0.12720093587382592, + "sd": 0.35665240203008014, + "sem": 0.03987495076389216, + "df": 79, + "critical": 1.9905, + "moe": 0.07937108949552733, + "p75": 6.5, + "p99": 6.699999809265137, + "p995": 6.699999809265137, + "p999": 6.699999809265137, + "sampleCount": 80, + "median": 6.400000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 1.0579857315781327, + "samples": [], + "totalTime": 502.80000019073486, + "min": 5, + "max": 7, + "hz": 177.00875092728373, + "period": 5.64943820439028, + "mean": 5.64943820439028, + "variance": 0.08048263317720879, + "sd": 0.2836946125276418, + "sem": 0.030071568784852603, + "df": 88, + "critical": 1.9876, + "moe": 0.05977025011677303, + "p75": 5.700000286102295, + "p99": 7, + "p995": 7, + "p999": 7, + "sampleCount": 89, + "median": 5.599999904632568 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 0.5415398192828255, + "samples": [], + "totalTime": 503.90000009536743, + "min": 10.199999809265137, + "max": 11.300000190734863, + "hz": 91.28795394184183, + "period": 10.954347828160161, + "mean": 10.954347828160161, + "variance": 0.03986957219262076, + "sd": 0.19967366424398778, + "sem": 0.029440275648749698, + "df": 45, + "critical": 2.015, + "moe": 0.05932215543223065, + "p75": 11.199999809265137, + "p99": 11.300000190734863, + "p995": 11.300000190734863, + "p999": 11.300000190734863, + "sampleCount": 46, + "median": 10.900000095367432 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 1.0948280082771111, + "samples": [], + "totalTime": 508.09999990463257, + "min": 8.699999809265137, + "max": 10.300000190734863, + "hz": 106.27829169481498, + "period": 9.409259257493195, + "mean": 9.409259257493195, + "variance": 0.14236547512081338, + "sd": 0.37731349713575496, + "sem": 0.05134586339153788, + "df": 53, + "critical": 2.0063, + "moe": 0.10301520572244244, + "p75": 9.599999904632568, + "p99": 10.300000190734863, + "p995": 10.300000190734863, + "p999": 10.300000190734863, + "sampleCount": 54, + "median": 9.450000047683716 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 1.3762479563243302, + "samples": [], + "totalTime": 508, + "min": 24.09999990463257, + "max": 26.600000381469727, + "hz": 39.37007874015748, + "period": 25.4, + "mean": 25.4, + "variance": 0.5578948422482667, + "sd": 0.7469235852804935, + "sem": 0.16701719106850446, + "df": 19, + "critical": 2.093, + "moe": 0.34956698090637983, + "p75": 25.90000009536743, + "p99": 26.600000381469727, + "p995": 26.600000381469727, + "p999": 26.600000381469727, + "sampleCount": 20, + "median": 25.40000009536743 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 22.724850932569552, + "samples": [], + "totalTime": 502.59999990463257, + "min": 30.299999713897705, + "max": 84.7999997138977, + "hz": 27.855153208628085, + "period": 35.89999999318804, + "mean": 35.89999999318804, + "variance": 199.71538253930902, + "sd": 14.132069294314581, + "sem": 3.7769543903909537, + "df": 13, + "critical": 2.16, + "moe": 8.15822148324446, + "p75": 32.90000009536743, + "p99": 84.7999997138977, + "p995": 84.7999997138977, + "p999": 84.7999997138977, + "sampleCount": 14, + "median": 32.30000019073486 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 1.0613789902283077, + "samples": [], + "totalTime": 509.30000019073486, + "min": 41.5, + "max": 43.59999990463257, + "hz": 23.561751414698513, + "period": 42.44166668256124, + "mean": 42.44166668256124, + "variance": 0.502651513706572, + "sd": 0.7089792054119585, + "sem": 0.20466466754722062, + "df": 11, + "critical": 2.201, + "moe": 0.4504669332714326, + "p75": 42.90000009536743, + "p99": 43.59999990463257, + "p995": 43.59999990463257, + "p999": 43.59999990463257, + "sampleCount": 12, + "median": 42.44999980926514 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 0.880743983397921, + "samples": [], + "totalTime": 501.09999990463257, + "min": 4.299999713897705, + "max": 5.400000095367432, + "hz": 201.55657557218504, + "period": 4.9613861376696295, + "mean": 4.9613861376696295, + "variance": 0.048994064100693485, + "sd": 0.22134602797586742, + "sem": 0.022024752974124876, + "df": 100, + "critical": 1.984, + "moe": 0.04369710990066376, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 101, + "median": 5 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.5300399859843834, + "samples": [], + "totalTime": 500.6000003814697, + "min": 5.599999904632568, + "max": 7, + "hz": 163.80343575212535, + "period": 6.104878053432557, + "mean": 6.104878053432557, + "variance": 0.18071666380975315, + "sd": 0.42510782609798325, + "sem": 0.04694530598236076, + "df": 81, + "critical": 1.9897, + "moe": 0.0934070753131032, + "p75": 6.5, + "p99": 7, + "p995": 7, + "p999": 7, + "sampleCount": 82, + "median": 6 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.654424144251816, + "samples": [], + "totalTime": 502.80000019073486, + "min": 0.19999980926513672, + "max": 5.700000286102295, + "hz": 216.78599832667334, + "period": 4.6128440384471086, + "mean": 4.6128440384471086, + "variance": 1.2785372211914887, + "sd": 1.1307242020897441, + "sem": 0.108303736209727, + "df": 108, + "critical": 1.9824, + "moe": 0.2147013266621628, + "p75": 4.800000190734863, + "p99": 5.700000286102295, + "p995": 5.700000286102295, + "p999": 5.700000286102295, + "sampleCount": 109, + "median": 4.699999809265137 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.806933961234032, + "samples": [], + "totalTime": 504.1000003814697, + "min": 4, + "max": 6.099999904632568, + "hz": 212.25947216629524, + "period": 4.711214956836166, + "mean": 4.711214956836166, + "variance": 0.1972315366674985, + "sd": 0.4441075733057234, + "sem": 0.04293349961761647, + "df": 106, + "critical": 1.9828, + "moe": 0.08512854304180993, + "p75": 5.099999904632568, + "p99": 5.300000190734863, + "p995": 6.099999904632568, + "p999": 6.099999904632568, + "sampleCount": 107, + "median": 4.900000095367432 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 3.7698052699654943, + "samples": [], + "totalTime": 505.80000019073486, + "min": 12.900000095367432, + "max": 19.59999990463257, + "hz": 71.17437719735976, + "period": 14.050000005298191, + "mean": 14.050000005298191, + "variance": 2.447142900739427, + "sd": 1.5643346511342855, + "sem": 0.26072244185571425, + "df": 35, + "critical": 2.0315, + "moe": 0.5296576406298834, + "p75": 13.900000095367432, + "p99": 19.59999990463257, + "p995": 19.59999990463257, + "p999": 19.59999990463257, + "sampleCount": 36, + "median": 13.600000143051147 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 23.06059645897704, + "samples": [], + "totalTime": 503.7999997138977, + "min": 0.8999996185302734, + "max": 62.59999990463257, + "hz": 176.65740383196126, + "period": 5.660674154088738, + "mean": 5.660674154088738, + "variance": 38.38923123061112, + "sd": 6.195904391661569, + "sem": 0.6567645519883358, + "df": 88, + "critical": 1.9876, + "moe": 1.3053852235320162, + "p75": 5.400000095367432, + "p99": 62.59999990463257, + "p995": 62.59999990463257, + "p999": 62.59999990463257, + "sampleCount": 89, + "median": 5.099999904632568 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 3.7244456522874954, + "samples": [], + "totalTime": 504.1000003814697, + "min": 4.5, + "max": 11, + "hz": 176.5522712411241, + "period": 5.664044948106401, + "mean": 5.664044948106401, + "variance": 1.0025561269847203, + "sd": 1.0012772478113743, + "sem": 0.10613517599786595, + "df": 88, + "critical": 1.9876, + "moe": 0.21095427581335838, + "p75": 5.700000286102295, + "p99": 11, + "p995": 11, + "p999": 11, + "sampleCount": 89, + "median": 5.5 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 7.810873233702524, + "samples": [], + "totalTime": 526.7999997138977, + "min": 49.19999980926514, + "max": 68.69999980926514, + "hz": 18.982536077127843, + "period": 52.67999997138977, + "mean": 52.67999997138977, + "variance": 33.09066613981466, + "sd": 5.752448708142877, + "sem": 1.8190840041024672, + "df": 9, + "critical": 2.262, + "moe": 4.114768017279781, + "p75": 51.39999961853027, + "p99": 68.69999980926514, + "p995": 68.69999980926514, + "p999": 68.69999980926514, + "sampleCount": 10, + "median": 50.84999990463257 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 8.6464413642579, + "samples": [], + "totalTime": 507.40000009536743, + "min": 4, + "max": 26.300000190734863, + "hz": 112.33740636438051, + "period": 8.901754387638025, + "mean": 8.901754387638025, + "variance": 8.41160412956901, + "sd": 2.900276560876395, + "sem": 0.38415101493181103, + "df": 56, + "critical": 2.0036, + "moe": 0.7696849735173766, + "p75": 9.099999904632568, + "p99": 26.300000190734863, + "p995": 26.300000190734863, + "p999": 26.300000190734863, + "sampleCount": 57, + "median": 8.599999904632568 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 12.261614670072522, + "samples": [], + "totalTime": 516.1999998092651, + "min": 26.5, + "max": 59, + "hz": 30.995738097466035, + "period": 32.26249998807907, + "mean": 32.26249998807907, + "variance": 55.13716676108045, + "sd": 7.425440509564429, + "sem": 1.8563601273911072, + "df": 15, + "critical": 2.131, + "moe": 3.9559034314704493, + "p75": 31.199999809265137, + "p99": 59, + "p995": 59, + "p999": 59, + "sampleCount": 16, + "median": 30.25 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 14.843357810341825, + "samples": [], + "totalTime": 2411.699999809265, + "min": 208.19999980926514, + "max": 368.69999980926514, + "hz": 4.146452710034778, + "period": 241.16999998092652, + "mean": 241.16999998092652, + "variance": 2504.5267734129166, + "sd": 50.045247260982904, + "sem": 15.8256967411009, + "df": 9, + "critical": 2.262, + "moe": 35.797726028370235, + "p75": 242.59999990463257, + "p99": 368.69999980926514, + "p995": 368.69999980926514, + "p999": 368.69999980926514, + "sampleCount": 10, + "median": 222.89999985694885 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 176.20958053855517, + "samples": [], + "totalTime": 1920.2999997138977, + "min": 36.69999980926514, + "max": 1538.0999999046326, + "hz": 5.20751965916257, + "period": 192.02999997138977, + "mean": 192.02999997138977, + "variance": 223775.2223129351, + "sd": 473.0488582725204, + "sem": 149.5911836683349, + "df": 9, + "critical": 2.262, + "moe": 338.37525745777356, + "p75": 49.09999990463257, + "p99": 1538.0999999046326, + "p995": 1538.0999999046326, + "p999": 1538.0999999046326, + "sampleCount": 10, + "median": 38.85000014305115 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/dm-sqlite-prev.json b/bench-results/dm-sqlite-prev.json new file mode 100644 index 000000000..2382de6c1 --- /dev/null +++ b/bench-results/dm-sqlite-prev.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 36.0195988218897, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 91, + "hz": 5700.8598345572045, + "period": 0.17541213589189597, + "mean": 0.17541213589189597, + "variance": 2.9626618896441888, + "sd": 1.7212384755298114, + "sem": 0.03223609573120864, + "df": 2850, + "critical": 1.96, + "moe": 0.06318274763316893, + "p75": 0.19999980926513672, + "p99": 0.3000001907348633, + "p995": 0.3000001907348633, + "p999": 6.199999809265137, + "sampleCount": 2851, + "median": 0.10000038146972656 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 14.985733209417354, + "samples": [], + "totalTime": 500.1999988555908, + "min": 0, + "max": 37.40000009536743, + "hz": 6725.309891436438, + "period": 0.148692032953505, + "mean": 0.148692032953505, + "variance": 0.4347856843371625, + "sd": 0.6593828056123109, + "sem": 0.011368669062281221, + "df": 3363, + "critical": 1.96, + "moe": 0.022282591362071193, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.6999998092651367, + "sampleCount": 3364, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 56.12247126388424, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 143.2999997138977, + "hz": 5248.950215963754, + "period": 0.190514285496303, + "mean": 0.190514285496303, + "variance": 7.8117049251712665, + "sd": 2.79494274094681, + "sem": 0.0545516964955393, + "df": 2624, + "critical": 1.96, + "moe": 0.10692132513125703, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.40000009536743164, + "sampleCount": 2625, + "median": 0.10000038146972656 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 225.67639860784672, + "samples": [], + "totalTime": 720, + "min": 0.09999990463256836, + "max": 718.5, + "hz": 13.88888888888889, + "period": 72, + "mean": 72, + "variance": 51600.28222220315, + "sd": 227.1569550381479, + "sem": 71.83333642690081, + "df": 9, + "critical": 2.262, + "moe": 162.48700699764964, + "p75": 0.20000028610229492, + "p99": 718.5, + "p995": 718.5, + "p999": 718.5, + "sampleCount": 10, + "median": 0.19999980926513672 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 44.799888908634415, + "samples": [], + "totalTime": 500.09999990463257, + "min": 0, + "max": 109.69999980926514, + "hz": 10091.981605603773, + "period": 0.09908856744692542, + "mean": 0.09908856744692542, + "variance": 2.5889408945746286, + "sd": 1.6090186122523968, + "sem": 0.02264875925376524, + "df": 5046, + "critical": 1.96, + "moe": 0.04439156813737987, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 9.099999904632568, + "sampleCount": 5047, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 15.541387629023589, + "samples": [], + "totalTime": 500.59999990463257, + "min": 3.9000000953674316, + "max": 43.59999990463257, + "hz": 203.7554934467272, + "period": 4.9078431363199275, + "mean": 4.9078431363199275, + "variance": 15.078749694457665, + "sd": 3.8831365794236063, + "sem": 0.38448781431591317, + "df": 101, + "critical": 1.9838, + "moe": 0.7627469260399086, + "p75": 4.600000381469727, + "p99": 6.300000190734863, + "p995": 43.59999990463257, + "p999": 43.59999990463257, + "sampleCount": 102, + "median": 4.5 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 1.3541077556191112, + "samples": [], + "totalTime": 1165.4000000953674, + "min": 113.69999980926514, + "max": 120.59999990463257, + "hz": 8.580744807947209, + "period": 116.54000000953674, + "mean": 116.54000000953674, + "variance": 4.867111296759727, + "sd": 2.2061530537928977, + "sem": 0.6976468516921529, + "df": 9, + "critical": 2.262, + "moe": 1.57807717852765, + "p75": 117.5, + "p99": 120.59999990463257, + "p995": 120.59999990463257, + "p999": 120.59999990463257, + "sampleCount": 10, + "median": 116.60000014305115 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 10.381318018038593, + "samples": [], + "totalTime": 500.29999828338623, + "min": 0.19999980926513672, + "max": 23.40000009536743, + "hz": 2452.528491325293, + "period": 0.4077424598886603, + "mean": 0.4077424598886603, + "variance": 0.5722809480233025, + "sd": 0.7564925300512243, + "sem": 0.021596449722252695, + "df": 1226, + "critical": 1.96, + "moe": 0.04232904145561528, + "p75": 0.40000009536743164, + "p99": 1.1999998092651367, + "p995": 1.3999996185302734, + "p999": 12.799999713897705, + "sampleCount": 1227, + "median": 0.40000009536743164 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 2.3280570034885253, + "samples": [], + "totalTime": 501, + "min": 4, + "max": 9.599999904632568, + "hz": 207.58483033932134, + "period": 4.8173076923076925, + "mean": 4.8173076923076925, + "variance": 0.332513065380897, + "sd": 0.5766394587442807, + "sem": 0.05654415100855133, + "df": 103, + "critical": 1.9834, + "moe": 0.1121496691103607, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 9.599999904632568, + "p999": 9.599999904632568, + "sampleCount": 104, + "median": 4.700000286102295 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.9220762982786632, + "samples": [], + "totalTime": 1173.9000000953674, + "min": 110.2999997138977, + "max": 120, + "hz": 8.51861316908391, + "period": 117.39000000953675, + "mean": 117.39000000953675, + "variance": 9.94988934262599, + "sd": 3.1543445186957606, + "sem": 0.9974913203946182, + "df": 9, + "critical": 2.262, + "moe": 2.2563253667326264, + "p75": 118.89999961853027, + "p99": 120, + "p995": 120, + "p999": 120, + "sampleCount": 10, + "median": 118.60000014305115 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 2.3657831258017725, + "samples": [], + "totalTime": 502.4000005722046, + "min": 2.5, + "max": 4.599999904632568, + "hz": 316.4808913592918, + "period": 3.1597484312717268, + "mean": 3.1597484312717268, + "variance": 0.2312809460012222, + "sd": 0.4809167765853279, + "sem": 0.03813918122694527, + "df": 158, + "critical": 1.96, + "moe": 0.07475279520481273, + "p75": 3.4000000953674316, + "p99": 4.599999904632568, + "p995": 4.599999904632568, + "p999": 4.599999904632568, + "sampleCount": 159, + "median": 3 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 10.270609247201493, + "samples": [], + "totalTime": 501.7000002861023, + "min": 3.9000000953674316, + "max": 30.09999990463257, + "hz": 211.28164229529966, + "period": 4.7330188706236065, + "mean": 4.7330188706236065, + "variance": 6.3698517064285864, + "sd": 2.5238565146276812, + "sem": 0.24513861512761465, + "df": 105, + "critical": 1.983, + "moe": 0.48610987379805987, + "p75": 5, + "p99": 5.299999713897705, + "p995": 30.09999990463257, + "p999": 30.09999990463257, + "sampleCount": 106, + "median": 4.5 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 3.037847878751112, + "samples": [], + "totalTime": 1194.1999998092651, + "min": 112, + "max": 126.09999990463257, + "hz": 8.373806733878057, + "period": 119.41999998092652, + "mean": 119.41999998092652, + "variance": 25.72177752855092, + "sd": 5.0716641774225275, + "sem": 1.6038010328139498, + "df": 9, + "critical": 2.262, + "moe": 3.6277979362251545, + "p75": 123.30000019073486, + "p99": 126.09999990463257, + "p995": 126.09999990463257, + "p999": 126.09999990463257, + "sampleCount": 10, + "median": 119.95000004768372 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 27.71661474762364, + "samples": [], + "totalTime": 509.7000002861023, + "min": 19.799999713897705, + "max": 87.40000009536743, + "hz": 31.391014304530035, + "period": 31.856250017881393, + "mean": 31.856250017881393, + "variance": 274.6772914318244, + "sd": 16.57339106615856, + "sem": 4.14334776653964, + "df": 15, + "critical": 2.131, + "moe": 8.829474090495973, + "p75": 35.09999990463257, + "p99": 87.40000009536743, + "p995": 87.40000009536743, + "p999": 87.40000009536743, + "sampleCount": 16, + "median": 32.44999980926514 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 7.899701973274932, + "samples": [], + "totalTime": 504.19999980926514, + "min": 3.8999996185302734, + "max": 24.09999990463257, + "hz": 208.25069424776018, + "period": 4.801904760088239, + "mean": 4.801904760088239, + "variance": 3.841534786987685, + "sd": 1.9599833639568691, + "sem": 0.19127479078634202, + "df": 104, + "critical": 1.9832, + "moe": 0.37933616508747353, + "p75": 5.099999904632568, + "p99": 5.200000286102295, + "p995": 24.09999990463257, + "p999": 24.09999990463257, + "sampleCount": 105, + "median": 4.899999618530273 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.288555303224698, + "samples": [], + "totalTime": 1155.3000001907349, + "min": 111.69999980926514, + "max": 118.7999997138977, + "hz": 8.655760407122864, + "period": 115.53000001907348, + "mean": 115.53000001907348, + "variance": 4.331222265455491, + "sd": 2.081158875592032, + "sem": 0.6581202219545826, + "df": 9, + "critical": 2.262, + "moe": 1.4886679420612658, + "p75": 117, + "p99": 118.7999997138977, + "p995": 118.7999997138977, + "p999": 118.7999997138977, + "sampleCount": 10, + "median": 115.30000019073486 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 31.22881086155448, + "samples": [], + "totalTime": 500.3999996185303, + "min": 3.1000003814697266, + "max": 83, + "hz": 243.80495622103163, + "period": 4.101639341135494, + "mean": 4.101639341135494, + "variance": 52.10429484506014, + "sd": 7.2183304749131665, + "sem": 0.6535169347277106, + "df": 121, + "critical": 1.96, + "moe": 1.2808931920663127, + "p75": 3.5, + "p99": 7.200000286102295, + "p995": 83, + "p999": 83, + "sampleCount": 122, + "median": 3.3000001907348633 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 5.498594713899634, + "samples": [], + "totalTime": 506, + "min": 19.700000286102295, + "max": 33, + "hz": 45.45454545454545, + "period": 22, + "mean": 22, + "variance": 7.824545386054338, + "sd": 2.7972388861258057, + "sem": 0.583264627318187, + "df": 22, + "critical": 2.074, + "moe": 1.2096908370579196, + "p75": 22.09999990463257, + "p99": 33, + "p995": 33, + "p999": 33, + "sampleCount": 23, + "median": 21.100000381469727 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 13.127087072279933, + "samples": [], + "totalTime": 910.6999998092651, + "min": 82.90000009536743, + "max": 137.59999990463257, + "hz": 10.980564403309955, + "period": 91.06999998092651, + "mean": 91.06999998092651, + "variance": 279.32010952885946, + "sd": 16.712872569635042, + "sem": 5.285074356419779, + "df": 9, + "critical": 2.262, + "moe": 11.95483819422154, + "p75": 89.5, + "p99": 137.59999990463257, + "p995": 137.59999990463257, + "p999": 137.59999990463257, + "sampleCount": 10, + "median": 84.70000004768372 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 16.238865100255325, + "samples": [], + "totalTime": 4095.3999996185303, + "min": 368.30000019073486, + "max": 672.3999996185303, + "hz": 2.4417639304906626, + "period": 409.539999961853, + "mean": 409.539999961853, + "variance": 8644.080421233282, + "sd": 92.9735468896034, + "sem": 29.40081703156101, + "df": 9, + "critical": 2.262, + "moe": 66.50464812539101, + "p75": 388.19999980926514, + "p99": 672.3999996185303, + "p995": 672.3999996185303, + "p999": 672.3999996185303, + "sampleCount": 10, + "median": 379.7999999523163 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.29894109039711086, + "samples": [], + "totalTime": 501.19999980926514, + "min": 4.5, + "max": 4.900000095367432, + "hz": 209.49720678363613, + "period": 4.7733333315168105, + "mean": 4.7733333315168105, + "variance": 0.005435894587155826, + "sd": 0.07372851949656813, + "sem": 0.007195166755508819, + "df": 104, + "critical": 1.9832, + "moe": 0.01426945470952509, + "p75": 4.800000190734863, + "p99": 4.900000095367432, + "p995": 4.900000095367432, + "p999": 4.900000095367432, + "sampleCount": 105, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.33772317289516374, + "samples": [], + "totalTime": 504.09999990463257, + "min": 4.5, + "max": 5, + "hz": 208.29200559385893, + "period": 4.800952380044119, + "mean": 4.800952380044119, + "variance": 0.007018313919717984, + "sd": 0.0837753777652956, + "sem": 0.008175639727244291, + "df": 104, + "critical": 1.9832, + "moe": 0.01621392870707088, + "p75": 4.899999618530273, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 105, + "median": 4.800000190734863 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 0.42604859863787775, + "samples": [], + "totalTime": 502.80000019073486, + "min": 4.400000095367432, + "max": 5.099999904632568, + "hz": 204.85282410685645, + "period": 4.8815533999100476, + "mean": 4.8815533999100476, + "variance": 0.011323049261381, + "sd": 0.10640981750468798, + "sem": 0.010484870867148837, + "df": 102, + "critical": 1.9836, + "moe": 0.020797789852076434, + "p75": 4.900000095367432, + "p99": 5, + "p995": 5.099999904632568, + "p999": 5.099999904632568, + "sampleCount": 103, + "median": 4.900000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 1.1163568892731741, + "samples": [], + "totalTime": 500.6000003814697, + "min": 4.399999618530273, + "max": 5.600000381469727, + "hz": 217.73871337782515, + "period": 4.592660553958438, + "mean": 4.592660553958438, + "variance": 0.07290859495587028, + "sd": 0.27001591611582876, + "sem": 0.025862834188381027, + "df": 108, + "critical": 1.9824, + "moe": 0.051270482495046545, + "p75": 4.599999904632568, + "p99": 5.599999904632568, + "p995": 5.600000381469727, + "p999": 5.600000381469727, + "sampleCount": 109, + "median": 4.5 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 2, + "rme": 0.4870733757898279, + "samples": [], + "totalTime": 500.5, + "min": 5.5, + "max": 6.599999904632568, + "hz": 167.83216783216784, + "period": 5.958333333333333, + "mean": 5.958333333333333, + "variance": 0.01788151967000695, + "sd": 0.13372179953174035, + "sem": 0.014590244486188347, + "df": 83, + "critical": 1.9891, + "moe": 0.029021455307477243, + "p75": 6, + "p99": 6.599999904632568, + "p995": 6.599999904632568, + "p999": 6.599999904632568, + "sampleCount": 84, + "median": 5.900000095367432 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 3, + "rme": 1.5435666074360017, + "samples": [], + "totalTime": 504.69999980926514, + "min": 5.299999713897705, + "max": 6.699999809265137, + "hz": 162.47275615412963, + "period": 6.154878046454453, + "mean": 6.154878046454453, + "variance": 0.18695122118351756, + "sd": 0.4323785623542379, + "sem": 0.04774822448282668, + "df": 81, + "critical": 1.9897, + "moe": 0.09500464225348025, + "p75": 6.5, + "p99": 6.699999809265137, + "p995": 6.699999809265137, + "p999": 6.699999809265137, + "sampleCount": 82, + "median": 6.400000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 0.9011374467074248, + "samples": [], + "totalTime": 503, + "min": 5, + "max": 6.799999713897705, + "hz": 176.93836978131213, + "period": 5.651685393258427, + "mean": 5.651685393258427, + "variance": 0.058434598126903076, + "sd": 0.24173249290673166, + "sem": 0.025623593000978804, + "df": 88, + "critical": 1.9876, + "moe": 0.05092945344874547, + "p75": 5.700000286102295, + "p99": 6.799999713897705, + "p995": 6.799999713897705, + "p999": 6.799999713897705, + "sampleCount": 89, + "median": 5.599999904632568 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 14.460567448734201, + "samples": [], + "totalTime": 506.80000019073486, + "min": 10.099999904632568, + "max": 47.200000286102295, + "hz": 84.84609310145402, + "period": 11.786046516063601, + "mean": 11.786046516063601, + "variance": 30.653134465212332, + "sd": 5.536527292916773, + "sem": 0.8443124967772538, + "df": 42, + "critical": 2.0186, + "moe": 1.7043292059945647, + "p75": 11.099999904632568, + "p99": 47.200000286102295, + "p995": 47.200000286102295, + "p999": 47.200000286102295, + "sampleCount": 43, + "median": 11 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 1.2977533495068148, + "samples": [], + "totalTime": 504.40000009536743, + "min": 8.800000190734863, + "max": 10.900000095367432, + "hz": 105.07533701423321, + "period": 9.516981133874857, + "mean": 9.516981133874857, + "variance": 0.20066762318635661, + "sd": 0.4479593990378555, + "sem": 0.061531955677955656, + "df": 52, + "critical": 2.0072, + "moe": 0.1235069414367926, + "p75": 9.699999809265137, + "p99": 10.900000095367432, + "p995": 10.900000095367432, + "p999": 10.900000095367432, + "sampleCount": 53, + "median": 9.5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 2.2825788090683328, + "samples": [], + "totalTime": 525.9000000953674, + "min": 24.300000190734863, + "max": 28.699999809265137, + "hz": 38.030043727653876, + "period": 26.295000004768372, + "mean": 26.295000004768372, + "variance": 1.6447104490681934, + "sd": 1.2824626501649836, + "sem": 0.2867673664373435, + "df": 19, + "critical": 2.093, + "moe": 0.6002040979533599, + "p75": 27.5, + "p99": 28.699999809265137, + "p995": 28.699999809265137, + "p999": 28.699999809265137, + "sampleCount": 20, + "median": 26.350000143051147 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 15.878597605329425, + "samples": [], + "totalTime": 515.1999998092651, + "min": 29.5, + "max": 69.59999990463257, + "hz": 29.114906843076916, + "period": 34.34666665395101, + "mean": 34.34666665395101, + "variance": 96.96838047000342, + "sd": 9.847252432531798, + "sem": 2.542549645139742, + "df": 14, + "critical": 2.145, + "moe": 5.453768988824746, + "p75": 33.09999990463257, + "p99": 69.59999990463257, + "p995": 69.59999990463257, + "p999": 69.59999990463257, + "sampleCount": 15, + "median": 31.800000190734863 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 2.253250274126148, + "samples": [], + "totalTime": 525.6000003814697, + "min": 42.30000019073486, + "max": 47.19999980926514, + "hz": 22.83105021174019, + "period": 43.800000031789146, + "mean": 43.800000031789146, + "variance": 2.412727352489183, + "sd": 1.553295642332516, + "sem": 0.4483978286158754, + "df": 11, + "critical": 2.201, + "moe": 0.9869236207835418, + "p75": 44.700000286102295, + "p99": 47.19999980926514, + "p995": 47.19999980926514, + "p999": 47.19999980926514, + "sampleCount": 12, + "median": 43.049999952316284 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 0.9108207995943646, + "samples": [], + "totalTime": 503.09999990463257, + "min": 4.400000095367432, + "max": 5.400000095367432, + "hz": 202.74299347909974, + "period": 4.932352940241496, + "mean": 4.932352940241496, + "variance": 0.05230925926584761, + "sd": 0.22871217559598267, + "sem": 0.022645879871521193, + "df": 101, + "critical": 1.9838, + "moe": 0.04492489648912374, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 102, + "median": 4.950000047683716 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.3560077781249273, + "samples": [], + "totalTime": 505.80000019073486, + "min": 5.599999904632568, + "max": 7, + "hz": 162.11941472731945, + "period": 6.168292685252864, + "mean": 6.168292685252864, + "variance": 0.14490819919546574, + "sd": 0.38066809584658623, + "sem": 0.042037758752344466, + "df": 81, + "critical": 1.9897, + "moe": 0.08364252858953979, + "p75": 6.400000095367432, + "p99": 7, + "p995": 7, + "p999": 7, + "sampleCount": 82, + "median": 6.099999904632568 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.499392755790716, + "samples": [], + "totalTime": 503.5, + "min": 0.09999990463256836, + "max": 5.700000286102295, + "hz": 218.47070506454816, + "period": 4.577272727272727, + "mean": 4.577272727272727, + "variance": 1.1874603864528663, + "sd": 1.0897065597916102, + "sem": 0.10389944380168156, + "df": 109, + "critical": 1.9822, + "moe": 0.2059494775036932, + "p75": 4.900000095367432, + "p99": 5.700000286102295, + "p995": 5.700000286102295, + "p999": 5.700000286102295, + "sampleCount": 110, + "median": 4.700000286102295 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.9189691847011237, + "samples": [], + "totalTime": 500.09999990463257, + "min": 4, + "max": 6.300000190734863, + "hz": 213.95720859908928, + "period": 4.67383177480965, + "mean": 4.67383177480965, + "variance": 0.21893142928065012, + "sd": 0.4679010892065225, + "sem": 0.04523370562001554, + "df": 106, + "critical": 1.9828, + "moe": 0.0896893915033668, + "p75": 5, + "p99": 5.799999713897705, + "p995": 6.300000190734863, + "p999": 6.300000190734863, + "sampleCount": 107, + "median": 4.799999713897705 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 3.741092452206312, + "samples": [], + "totalTime": 505.80000019073486, + "min": 13, + "max": 20.299999713897705, + "hz": 69.19731116409977, + "period": 14.451428576878138, + "mean": 14.451428576878138, + "variance": 2.473747802093277, + "sd": 1.57281524728535, + "sem": 0.2658542996290195, + "df": 34, + "critical": 2.0336, + "moe": 0.5406413037255741, + "p75": 14.800000190734863, + "p99": 20.299999713897705, + "p995": 20.299999713897705, + "p999": 20.299999713897705, + "sampleCount": 35, + "median": 13.900000095367432 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 24.049421818117846, + "samples": [], + "totalTime": 501.90000009536743, + "min": 0.8999996185302734, + "max": 65, + "hz": 167.36401670460037, + "period": 5.975000001135326, + "mean": 5.975000001135326, + "variance": 43.838042186886454, + "sd": 6.621030296478521, + "sem": 0.722413631243065, + "df": 83, + "critical": 1.9891, + "moe": 1.4369529539055808, + "p75": 6, + "p99": 65, + "p995": 65, + "p999": 65, + "sampleCount": 84, + "median": 5.400000095367432 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 4.004305898951129, + "samples": [], + "totalTime": 504.19999980926514, + "min": 5.199999809265137, + "max": 11.900000095367432, + "hz": 166.60055539820812, + "period": 6.002380950110299, + "mean": 6.002380950110299, + "variance": 1.2265002903197229, + "sd": 1.1074747357478287, + "sem": 0.12083540016227719, + "df": 83, + "critical": 1.9891, + "moe": 0.24035369446278557, + "p75": 6, + "p99": 11.900000095367432, + "p995": 11.900000095367432, + "p999": 11.900000095367432, + "sampleCount": 84, + "median": 5.800000190734863 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 7.995059327038918, + "samples": [], + "totalTime": 551.6999998092651, + "min": 51, + "max": 72, + "hz": 18.12579300971039, + "period": 55.16999998092651, + "mean": 55.16999998092651, + "variance": 38.024555677202024, + "sd": 6.166405409734429, + "sem": 1.9499886070744625, + "df": 9, + "critical": 2.262, + "moe": 4.4108742292024345, + "p75": 55.09999990463257, + "p99": 72, + "p995": 72, + "p999": 72, + "sampleCount": 10, + "median": 53.40000009536743 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 8.523838873114142, + "samples": [], + "totalTime": 507.1000003814697, + "min": 4.199999809265137, + "max": 25.300000190734863, + "hz": 108.45986976656646, + "period": 9.220000006935813, + "mean": 9.220000006935813, + "variance": 8.446814840316812, + "sd": 2.906340454990917, + "sem": 0.39189086700524656, + "df": 54, + "critical": 2.0054, + "moe": 0.7858979446923214, + "p75": 9.400000095367432, + "p99": 25.300000190734863, + "p995": 25.300000190734863, + "p999": 25.300000190734863, + "sampleCount": 55, + "median": 8.800000190734863 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 14.157436787721728, + "samples": [], + "totalTime": 504.59999990463257, + "min": 28.59999990463257, + "max": 65.7000002861023, + "hz": 27.74474832074107, + "period": 36.042857136045185, + "mean": 36.042857136045185, + "variance": 78.13186960849136, + "sd": 8.839223360029509, + "sem": 2.3623818127427993, + "df": 13, + "critical": 2.16, + "moe": 5.102744715524447, + "p75": 34.5, + "p99": 65.7000002861023, + "p995": 65.7000002861023, + "p999": 65.7000002861023, + "sampleCount": 14, + "median": 33.94999980926514 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 16.09077848820552, + "samples": [], + "totalTime": 2488.8999996185303, + "min": 214.09999990463257, + "max": 401.69999980926514, + "hz": 4.01783920669078, + "period": 248.88999996185302, + "mean": 248.88999996185302, + "variance": 3134.6121060409546, + "sd": 55.987606718281455, + "sem": 17.70483579715145, + "df": 9, + "critical": 2.262, + "moe": 40.04833857315658, + "p75": 248.2999997138977, + "p99": 401.69999980926514, + "p995": 401.69999980926514, + "p999": 401.69999980926514, + "sampleCount": 10, + "median": 230.65000009536743 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 176.5220959803493, + "samples": [], + "totalTime": 1887.0999999046326, + "min": 35.39999961853027, + "max": 1513.9000000953674, + "hz": 5.299136241060551, + "period": 188.70999999046325, + "mean": 188.70999999046325, + "variance": 216871.6476988057, + "sd": 465.6948010218771, + "sem": 147.26562657280402, + "df": 9, + "critical": 2.262, + "moe": 333.1148473076827, + "p75": 48.799999713897705, + "p99": 1513.9000000953674, + "p995": 1513.9000000953674, + "p999": 1513.9000000953674, + "sampleCount": 10, + "median": 38.85000014305115 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/bench-results/dm-sqlite.json b/bench-results/dm-sqlite.json new file mode 100644 index 000000000..2382de6c1 --- /dev/null +++ b/bench-results/dm-sqlite.json @@ -0,0 +1,1229 @@ +{ + "files": [ + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/clear.bench.ts", + "groups": [ + { + "fullName": "benchmarks/clear.bench.ts > clear (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "2073953325_0_0", + "name": "Onyx.clear() - 50 reports + 50 txns", + "rank": 1, + "rme": 36.0195988218897, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 91, + "hz": 5700.8598345572045, + "period": 0.17541213589189597, + "mean": 0.17541213589189597, + "variance": 2.9626618896441888, + "sd": 1.7212384755298114, + "sem": 0.03223609573120864, + "df": 2850, + "critical": 1.96, + "moe": 0.06318274763316893, + "p75": 0.19999980926513672, + "p99": 0.3000001907348633, + "p995": 0.3000001907348633, + "p999": 6.199999809265137, + "sampleCount": 2851, + "median": 0.10000038146972656 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "2073953325_1_0", + "name": "Onyx.clear() - 250 reports + 250 txns", + "rank": 1, + "rme": 14.985733209417354, + "samples": [], + "totalTime": 500.1999988555908, + "min": 0, + "max": 37.40000009536743, + "hz": 6725.309891436438, + "period": 0.148692032953505, + "mean": 0.148692032953505, + "variance": 0.4347856843371625, + "sd": 0.6593828056123109, + "sem": 0.011368669062281221, + "df": 3363, + "critical": 1.96, + "moe": 0.022282591362071193, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.6999998092651367, + "sampleCount": 3364, + "median": 0.09999990463256836 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "2073953325_2_0", + "name": "Onyx.clear() - 1000 reports + 1000 txns", + "rank": 1, + "rme": 56.12247126388424, + "samples": [], + "totalTime": 500.0999994277954, + "min": 0, + "max": 143.2999997138977, + "hz": 5248.950215963754, + "period": 0.190514285496303, + "mean": 0.190514285496303, + "variance": 7.8117049251712665, + "sd": 2.79494274094681, + "sem": 0.0545516964955393, + "df": 2624, + "critical": 1.96, + "moe": 0.10692132513125703, + "p75": 0.19999980926513672, + "p99": 0.2999997138977051, + "p995": 0.3000001907348633, + "p999": 0.40000009536743164, + "sampleCount": 2625, + "median": 0.10000038146972656 + } + ] + }, + { + "fullName": "benchmarks/clear.bench.ts > clear (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "2073953325_3_0", + "name": "Onyx.clear() - 5000 reports + 5000 txns", + "rank": 1, + "rme": 225.67639860784672, + "samples": [], + "totalTime": 720, + "min": 0.09999990463256836, + "max": 718.5, + "hz": 13.88888888888889, + "period": 72, + "mean": 72, + "variance": 51600.28222220315, + "sd": 227.1569550381479, + "sem": 71.83333642690081, + "df": 9, + "critical": 2.262, + "moe": 162.48700699764964, + "p75": 0.20000028610229492, + "p99": 718.5, + "p995": 718.5, + "p999": 718.5, + "sampleCount": 10, + "median": 0.19999980926513672 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/connect.bench.ts", + "groups": [ + { + "fullName": "benchmarks/connect.bench.ts > connect (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-9122576_0_0", + "name": "Onyx.connect() - register 50 individual key subscribers", + "rank": 1, + "rme": 44.799888908634415, + "samples": [], + "totalTime": 500.09999990463257, + "min": 0, + "max": 109.69999980926514, + "hz": 10091.981605603773, + "period": 0.09908856744692542, + "mean": 0.09908856744692542, + "variance": 2.5889408945746286, + "sd": 1.6090186122523968, + "sem": 0.02264875925376524, + "df": 5046, + "critical": 1.96, + "moe": 0.04439156813737987, + "p75": 0.09999990463256836, + "p99": 0.20000028610229492, + "p995": 0.20000028610229492, + "p999": 9.099999904632568, + "sampleCount": 5047, + "median": 0.09999990463256836 + }, + { + "id": "-9122576_0_1", + "name": "Onyx.connect() - collection subscriber for 50 reports", + "rank": 2, + "rme": 15.541387629023589, + "samples": [], + "totalTime": 500.59999990463257, + "min": 3.9000000953674316, + "max": 43.59999990463257, + "hz": 203.7554934467272, + "period": 4.9078431363199275, + "mean": 4.9078431363199275, + "variance": 15.078749694457665, + "sd": 3.8831365794236063, + "sem": 0.38448781431591317, + "df": 101, + "critical": 1.9838, + "moe": 0.7627469260399086, + "p75": 4.600000381469727, + "p99": 6.300000190734863, + "p995": 43.59999990463257, + "p999": 43.59999990463257, + "sampleCount": 102, + "median": 4.5 + }, + { + "id": "-9122576_0_2", + "name": "Notification throughput - write with 50 active subscribers", + "rank": 3, + "rme": 1.3541077556191112, + "samples": [], + "totalTime": 1165.4000000953674, + "min": 113.69999980926514, + "max": 120.59999990463257, + "hz": 8.580744807947209, + "period": 116.54000000953674, + "mean": 116.54000000953674, + "variance": 4.867111296759727, + "sd": 2.2061530537928977, + "sem": 0.6976468516921529, + "df": 9, + "critical": 2.262, + "moe": 1.57807717852765, + "p75": 117.5, + "p99": 120.59999990463257, + "p995": 120.59999990463257, + "p999": 120.59999990463257, + "sampleCount": 10, + "median": 116.60000014305115 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-9122576_1_0", + "name": "Onyx.connect() - register 250 individual key subscribers", + "rank": 1, + "rme": 10.381318018038593, + "samples": [], + "totalTime": 500.29999828338623, + "min": 0.19999980926513672, + "max": 23.40000009536743, + "hz": 2452.528491325293, + "period": 0.4077424598886603, + "mean": 0.4077424598886603, + "variance": 0.5722809480233025, + "sd": 0.7564925300512243, + "sem": 0.021596449722252695, + "df": 1226, + "critical": 1.96, + "moe": 0.04232904145561528, + "p75": 0.40000009536743164, + "p99": 1.1999998092651367, + "p995": 1.3999996185302734, + "p999": 12.799999713897705, + "sampleCount": 1227, + "median": 0.40000009536743164 + }, + { + "id": "-9122576_1_1", + "name": "Onyx.connect() - collection subscriber for 250 reports", + "rank": 2, + "rme": 2.3280570034885253, + "samples": [], + "totalTime": 501, + "min": 4, + "max": 9.599999904632568, + "hz": 207.58483033932134, + "period": 4.8173076923076925, + "mean": 4.8173076923076925, + "variance": 0.332513065380897, + "sd": 0.5766394587442807, + "sem": 0.05654415100855133, + "df": 103, + "critical": 1.9834, + "moe": 0.1121496691103607, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 9.599999904632568, + "p999": 9.599999904632568, + "sampleCount": 104, + "median": 4.700000286102295 + }, + { + "id": "-9122576_1_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.9220762982786632, + "samples": [], + "totalTime": 1173.9000000953674, + "min": 110.2999997138977, + "max": 120, + "hz": 8.51861316908391, + "period": 117.39000000953675, + "mean": 117.39000000953675, + "variance": 9.94988934262599, + "sd": 3.1543445186957606, + "sem": 0.9974913203946182, + "df": 9, + "critical": 2.262, + "moe": 2.2563253667326264, + "p75": 118.89999961853027, + "p99": 120, + "p995": 120, + "p999": 120, + "sampleCount": 10, + "median": 118.60000014305115 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-9122576_2_0", + "name": "Onyx.connect() - register 1000 individual key subscribers", + "rank": 1, + "rme": 2.3657831258017725, + "samples": [], + "totalTime": 502.4000005722046, + "min": 2.5, + "max": 4.599999904632568, + "hz": 316.4808913592918, + "period": 3.1597484312717268, + "mean": 3.1597484312717268, + "variance": 0.2312809460012222, + "sd": 0.4809167765853279, + "sem": 0.03813918122694527, + "df": 158, + "critical": 1.96, + "moe": 0.07475279520481273, + "p75": 3.4000000953674316, + "p99": 4.599999904632568, + "p995": 4.599999904632568, + "p999": 4.599999904632568, + "sampleCount": 159, + "median": 3 + }, + { + "id": "-9122576_2_1", + "name": "Onyx.connect() - collection subscriber for 1000 reports", + "rank": 2, + "rme": 10.270609247201493, + "samples": [], + "totalTime": 501.7000002861023, + "min": 3.9000000953674316, + "max": 30.09999990463257, + "hz": 211.28164229529966, + "period": 4.7330188706236065, + "mean": 4.7330188706236065, + "variance": 6.3698517064285864, + "sd": 2.5238565146276812, + "sem": 0.24513861512761465, + "df": 105, + "critical": 1.983, + "moe": 0.48610987379805987, + "p75": 5, + "p99": 5.299999713897705, + "p995": 30.09999990463257, + "p999": 30.09999990463257, + "sampleCount": 106, + "median": 4.5 + }, + { + "id": "-9122576_2_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 3.037847878751112, + "samples": [], + "totalTime": 1194.1999998092651, + "min": 112, + "max": 126.09999990463257, + "hz": 8.373806733878057, + "period": 119.41999998092652, + "mean": 119.41999998092652, + "variance": 25.72177752855092, + "sd": 5.0716641774225275, + "sem": 1.6038010328139498, + "df": 9, + "critical": 2.262, + "moe": 3.6277979362251545, + "p75": 123.30000019073486, + "p99": 126.09999990463257, + "p995": 126.09999990463257, + "p999": 126.09999990463257, + "sampleCount": 10, + "median": 119.95000004768372 + } + ] + }, + { + "fullName": "benchmarks/connect.bench.ts > connect (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-9122576_3_0", + "name": "Onyx.connect() - register 5000 individual key subscribers", + "rank": 2, + "rme": 27.71661474762364, + "samples": [], + "totalTime": 509.7000002861023, + "min": 19.799999713897705, + "max": 87.40000009536743, + "hz": 31.391014304530035, + "period": 31.856250017881393, + "mean": 31.856250017881393, + "variance": 274.6772914318244, + "sd": 16.57339106615856, + "sem": 4.14334776653964, + "df": 15, + "critical": 2.131, + "moe": 8.829474090495973, + "p75": 35.09999990463257, + "p99": 87.40000009536743, + "p995": 87.40000009536743, + "p999": 87.40000009536743, + "sampleCount": 16, + "median": 32.44999980926514 + }, + { + "id": "-9122576_3_1", + "name": "Onyx.connect() - collection subscriber for 5000 reports", + "rank": 1, + "rme": 7.899701973274932, + "samples": [], + "totalTime": 504.19999980926514, + "min": 3.8999996185302734, + "max": 24.09999990463257, + "hz": 208.25069424776018, + "period": 4.801904760088239, + "mean": 4.801904760088239, + "variance": 3.841534786987685, + "sd": 1.9599833639568691, + "sem": 0.19127479078634202, + "df": 104, + "critical": 1.9832, + "moe": 0.37933616508747353, + "p75": 5.099999904632568, + "p99": 5.200000286102295, + "p995": 24.09999990463257, + "p999": 24.09999990463257, + "sampleCount": 105, + "median": 4.899999618530273 + }, + { + "id": "-9122576_3_2", + "name": "Notification throughput - write with 100 active subscribers", + "rank": 3, + "rme": 1.288555303224698, + "samples": [], + "totalTime": 1155.3000001907349, + "min": 111.69999980926514, + "max": 118.7999997138977, + "hz": 8.655760407122864, + "period": 115.53000001907348, + "mean": 115.53000001907348, + "variance": 4.331222265455491, + "sd": 2.081158875592032, + "sem": 0.6581202219545826, + "df": 9, + "critical": 2.262, + "moe": 1.4886679420612658, + "p75": 117, + "p99": 118.7999997138977, + "p995": 118.7999997138977, + "p999": 118.7999997138977, + "sampleCount": 10, + "median": 115.30000019073486 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/init.bench.ts", + "groups": [ + { + "fullName": "benchmarks/init.bench.ts > init (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "605173368_0_0", + "name": "Onyx.init() with 50 initialKeyStates", + "rank": 1, + "rme": 31.22881086155448, + "samples": [], + "totalTime": 500.3999996185303, + "min": 3.1000003814697266, + "max": 83, + "hz": 243.80495622103163, + "period": 4.101639341135494, + "mean": 4.101639341135494, + "variance": 52.10429484506014, + "sd": 7.2183304749131665, + "sem": 0.6535169347277106, + "df": 121, + "critical": 1.96, + "moe": 1.2808931920663127, + "p75": 3.5, + "p99": 7.200000286102295, + "p995": 83, + "p999": 83, + "sampleCount": 122, + "median": 3.3000001907348633 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "605173368_1_0", + "name": "Onyx.init() with 250 initialKeyStates", + "rank": 1, + "rme": 5.498594713899634, + "samples": [], + "totalTime": 506, + "min": 19.700000286102295, + "max": 33, + "hz": 45.45454545454545, + "period": 22, + "mean": 22, + "variance": 7.824545386054338, + "sd": 2.7972388861258057, + "sem": 0.583264627318187, + "df": 22, + "critical": 2.074, + "moe": 1.2096908370579196, + "p75": 22.09999990463257, + "p99": 33, + "p995": 33, + "p999": 33, + "sampleCount": 23, + "median": 21.100000381469727 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "605173368_2_0", + "name": "Onyx.init() with 1000 initialKeyStates", + "rank": 1, + "rme": 13.127087072279933, + "samples": [], + "totalTime": 910.6999998092651, + "min": 82.90000009536743, + "max": 137.59999990463257, + "hz": 10.980564403309955, + "period": 91.06999998092651, + "mean": 91.06999998092651, + "variance": 279.32010952885946, + "sd": 16.712872569635042, + "sem": 5.285074356419779, + "df": 9, + "critical": 2.262, + "moe": 11.95483819422154, + "p75": 89.5, + "p99": 137.59999990463257, + "p995": 137.59999990463257, + "p999": 137.59999990463257, + "sampleCount": 10, + "median": 84.70000004768372 + } + ] + }, + { + "fullName": "benchmarks/init.bench.ts > init (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "605173368_3_0", + "name": "Onyx.init() with 5000 initialKeyStates", + "rank": 1, + "rme": 16.238865100255325, + "samples": [], + "totalTime": 4095.3999996185303, + "min": 368.30000019073486, + "max": 672.3999996185303, + "hz": 2.4417639304906626, + "period": 409.539999961853, + "mean": 409.539999961853, + "variance": 8644.080421233282, + "sd": 92.9735468896034, + "sem": 29.40081703156101, + "df": 9, + "critical": 2.262, + "moe": 66.50464812539101, + "p75": 388.19999980926514, + "p99": 672.3999996185303, + "p995": 672.3999996185303, + "p999": 672.3999996185303, + "sampleCount": 10, + "median": 379.7999999523163 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/merge.bench.ts", + "groups": [ + { + "fullName": "benchmarks/merge.bench.ts > merge (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-25802334_0_0", + "name": "Onyx.merge() - partial update 50 reports", + "rank": 1, + "rme": 0.29894109039711086, + "samples": [], + "totalTime": 501.19999980926514, + "min": 4.5, + "max": 4.900000095367432, + "hz": 209.49720678363613, + "period": 4.7733333315168105, + "mean": 4.7733333315168105, + "variance": 0.005435894587155826, + "sd": 0.07372851949656813, + "sem": 0.007195166755508819, + "df": 104, + "critical": 1.9832, + "moe": 0.01426945470952509, + "p75": 4.800000190734863, + "p99": 4.900000095367432, + "p995": 4.900000095367432, + "p999": 4.900000095367432, + "sampleCount": 105, + "median": 4.799999713897705 + }, + { + "id": "-25802334_0_1", + "name": "Onyx.mergeCollection() - partial update 50 reports", + "rank": 2, + "rme": 0.33772317289516374, + "samples": [], + "totalTime": 504.09999990463257, + "min": 4.5, + "max": 5, + "hz": 208.29200559385893, + "period": 4.800952380044119, + "mean": 4.800952380044119, + "variance": 0.007018313919717984, + "sd": 0.0837753777652956, + "sem": 0.008175639727244291, + "df": 104, + "critical": 1.9832, + "moe": 0.01621392870707088, + "p75": 4.899999618530273, + "p99": 4.900000095367432, + "p995": 5, + "p999": 5, + "sampleCount": 105, + "median": 4.800000190734863 + }, + { + "id": "-25802334_0_2", + "name": "Onyx.update() - mixed set/merge (50 ops)", + "rank": 3, + "rme": 0.42604859863787775, + "samples": [], + "totalTime": 502.80000019073486, + "min": 4.400000095367432, + "max": 5.099999904632568, + "hz": 204.85282410685645, + "period": 4.8815533999100476, + "mean": 4.8815533999100476, + "variance": 0.011323049261381, + "sd": 0.10640981750468798, + "sem": 0.010484870867148837, + "df": 102, + "critical": 1.9836, + "moe": 0.020797789852076434, + "p75": 4.900000095367432, + "p99": 5, + "p995": 5.099999904632568, + "p999": 5.099999904632568, + "sampleCount": 103, + "median": 4.900000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-25802334_1_0", + "name": "Onyx.merge() - partial update 250 reports", + "rank": 1, + "rme": 1.1163568892731741, + "samples": [], + "totalTime": 500.6000003814697, + "min": 4.399999618530273, + "max": 5.600000381469727, + "hz": 217.73871337782515, + "period": 4.592660553958438, + "mean": 4.592660553958438, + "variance": 0.07290859495587028, + "sd": 0.27001591611582876, + "sem": 0.025862834188381027, + "df": 108, + "critical": 1.9824, + "moe": 0.051270482495046545, + "p75": 4.599999904632568, + "p99": 5.599999904632568, + "p995": 5.600000381469727, + "p999": 5.600000381469727, + "sampleCount": 109, + "median": 4.5 + }, + { + "id": "-25802334_1_1", + "name": "Onyx.mergeCollection() - partial update 250 reports", + "rank": 2, + "rme": 0.4870733757898279, + "samples": [], + "totalTime": 500.5, + "min": 5.5, + "max": 6.599999904632568, + "hz": 167.83216783216784, + "period": 5.958333333333333, + "mean": 5.958333333333333, + "variance": 0.01788151967000695, + "sd": 0.13372179953174035, + "sem": 0.014590244486188347, + "df": 83, + "critical": 1.9891, + "moe": 0.029021455307477243, + "p75": 6, + "p99": 6.599999904632568, + "p995": 6.599999904632568, + "p999": 6.599999904632568, + "sampleCount": 84, + "median": 5.900000095367432 + }, + { + "id": "-25802334_1_2", + "name": "Onyx.update() - mixed set/merge (250 ops)", + "rank": 3, + "rme": 1.5435666074360017, + "samples": [], + "totalTime": 504.69999980926514, + "min": 5.299999713897705, + "max": 6.699999809265137, + "hz": 162.47275615412963, + "period": 6.154878046454453, + "mean": 6.154878046454453, + "variance": 0.18695122118351756, + "sd": 0.4323785623542379, + "sem": 0.04774822448282668, + "df": 81, + "critical": 1.9897, + "moe": 0.09500464225348025, + "p75": 6.5, + "p99": 6.699999809265137, + "p995": 6.699999809265137, + "p999": 6.699999809265137, + "sampleCount": 82, + "median": 6.400000095367432 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-25802334_2_0", + "name": "Onyx.merge() - partial update 1000 reports", + "rank": 1, + "rme": 0.9011374467074248, + "samples": [], + "totalTime": 503, + "min": 5, + "max": 6.799999713897705, + "hz": 176.93836978131213, + "period": 5.651685393258427, + "mean": 5.651685393258427, + "variance": 0.058434598126903076, + "sd": 0.24173249290673166, + "sem": 0.025623593000978804, + "df": 88, + "critical": 1.9876, + "moe": 0.05092945344874547, + "p75": 5.700000286102295, + "p99": 6.799999713897705, + "p995": 6.799999713897705, + "p999": 6.799999713897705, + "sampleCount": 89, + "median": 5.599999904632568 + }, + { + "id": "-25802334_2_1", + "name": "Onyx.mergeCollection() - partial update 1000 reports", + "rank": 3, + "rme": 14.460567448734201, + "samples": [], + "totalTime": 506.80000019073486, + "min": 10.099999904632568, + "max": 47.200000286102295, + "hz": 84.84609310145402, + "period": 11.786046516063601, + "mean": 11.786046516063601, + "variance": 30.653134465212332, + "sd": 5.536527292916773, + "sem": 0.8443124967772538, + "df": 42, + "critical": 2.0186, + "moe": 1.7043292059945647, + "p75": 11.099999904632568, + "p99": 47.200000286102295, + "p995": 47.200000286102295, + "p999": 47.200000286102295, + "sampleCount": 43, + "median": 11 + }, + { + "id": "-25802334_2_2", + "name": "Onyx.update() - mixed set/merge (1000 ops)", + "rank": 2, + "rme": 1.2977533495068148, + "samples": [], + "totalTime": 504.40000009536743, + "min": 8.800000190734863, + "max": 10.900000095367432, + "hz": 105.07533701423321, + "period": 9.516981133874857, + "mean": 9.516981133874857, + "variance": 0.20066762318635661, + "sd": 0.4479593990378555, + "sem": 0.061531955677955656, + "df": 52, + "critical": 2.0072, + "moe": 0.1235069414367926, + "p75": 9.699999809265137, + "p99": 10.900000095367432, + "p995": 10.900000095367432, + "p999": 10.900000095367432, + "sampleCount": 53, + "median": 9.5 + } + ] + }, + { + "fullName": "benchmarks/merge.bench.ts > merge (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-25802334_3_0", + "name": "Onyx.merge() - partial update 5000 reports", + "rank": 1, + "rme": 2.2825788090683328, + "samples": [], + "totalTime": 525.9000000953674, + "min": 24.300000190734863, + "max": 28.699999809265137, + "hz": 38.030043727653876, + "period": 26.295000004768372, + "mean": 26.295000004768372, + "variance": 1.6447104490681934, + "sd": 1.2824626501649836, + "sem": 0.2867673664373435, + "df": 19, + "critical": 2.093, + "moe": 0.6002040979533599, + "p75": 27.5, + "p99": 28.699999809265137, + "p995": 28.699999809265137, + "p999": 28.699999809265137, + "sampleCount": 20, + "median": 26.350000143051147 + }, + { + "id": "-25802334_3_1", + "name": "Onyx.mergeCollection() - partial update 5000 reports", + "rank": 2, + "rme": 15.878597605329425, + "samples": [], + "totalTime": 515.1999998092651, + "min": 29.5, + "max": 69.59999990463257, + "hz": 29.114906843076916, + "period": 34.34666665395101, + "mean": 34.34666665395101, + "variance": 96.96838047000342, + "sd": 9.847252432531798, + "sem": 2.542549645139742, + "df": 14, + "critical": 2.145, + "moe": 5.453768988824746, + "p75": 33.09999990463257, + "p99": 69.59999990463257, + "p995": 69.59999990463257, + "p999": 69.59999990463257, + "sampleCount": 15, + "median": 31.800000190734863 + }, + { + "id": "-25802334_3_2", + "name": "Onyx.update() - mixed set/merge (5000 ops)", + "rank": 3, + "rme": 2.253250274126148, + "samples": [], + "totalTime": 525.6000003814697, + "min": 42.30000019073486, + "max": 47.19999980926514, + "hz": 22.83105021174019, + "period": 43.800000031789146, + "mean": 43.800000031789146, + "variance": 2.412727352489183, + "sd": 1.553295642332516, + "sem": 0.4483978286158754, + "df": 11, + "critical": 2.201, + "moe": 0.9869236207835418, + "p75": 44.700000286102295, + "p99": 47.19999980926514, + "p995": 47.19999980926514, + "p999": 47.19999980926514, + "sampleCount": 12, + "median": 43.049999952316284 + } + ] + } + ] + }, + { + "filepath": "/Users/roryabraham/Expensidev/react-native-onyx/benchmarks/set.bench.ts", + "groups": [ + { + "fullName": "benchmarks/set.bench.ts > set (small (50 reports, 50 txns))", + "benchmarks": [ + { + "id": "-1033356040_0_0", + "name": "Onyx.set() - 50 reports individually", + "rank": 2, + "rme": 0.9108207995943646, + "samples": [], + "totalTime": 503.09999990463257, + "min": 4.400000095367432, + "max": 5.400000095367432, + "hz": 202.74299347909974, + "period": 4.932352940241496, + "mean": 4.932352940241496, + "variance": 0.05230925926584761, + "sd": 0.22871217559598267, + "sem": 0.022645879871521193, + "df": 101, + "critical": 1.9838, + "moe": 0.04492489648912374, + "p75": 5.099999904632568, + "p99": 5.400000095367432, + "p995": 5.400000095367432, + "p999": 5.400000095367432, + "sampleCount": 102, + "median": 4.950000047683716 + }, + { + "id": "-1033356040_0_1", + "name": "Onyx.multiSet() - full store (50 reports + 50 txns)", + "rank": 3, + "rme": 1.3560077781249273, + "samples": [], + "totalTime": 505.80000019073486, + "min": 5.599999904632568, + "max": 7, + "hz": 162.11941472731945, + "period": 6.168292685252864, + "mean": 6.168292685252864, + "variance": 0.14490819919546574, + "sd": 0.38066809584658623, + "sem": 0.042037758752344466, + "df": 81, + "critical": 1.9897, + "moe": 0.08364252858953979, + "p75": 6.400000095367432, + "p99": 7, + "p995": 7, + "p999": 7, + "sampleCount": 82, + "median": 6.099999904632568 + }, + { + "id": "-1033356040_0_2", + "name": "Onyx.setCollection() - 50 reports", + "rank": 1, + "rme": 4.499392755790716, + "samples": [], + "totalTime": 503.5, + "min": 0.09999990463256836, + "max": 5.700000286102295, + "hz": 218.47070506454816, + "period": 4.577272727272727, + "mean": 4.577272727272727, + "variance": 1.1874603864528663, + "sd": 1.0897065597916102, + "sem": 0.10389944380168156, + "df": 109, + "critical": 1.9822, + "moe": 0.2059494775036932, + "p75": 4.900000095367432, + "p99": 5.700000286102295, + "p995": 5.700000286102295, + "p999": 5.700000286102295, + "sampleCount": 110, + "median": 4.700000286102295 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (modest (250 reports, 250 txns))", + "benchmarks": [ + { + "id": "-1033356040_1_0", + "name": "Onyx.set() - 250 reports individually", + "rank": 1, + "rme": 1.9189691847011237, + "samples": [], + "totalTime": 500.09999990463257, + "min": 4, + "max": 6.300000190734863, + "hz": 213.95720859908928, + "period": 4.67383177480965, + "mean": 4.67383177480965, + "variance": 0.21893142928065012, + "sd": 0.4679010892065225, + "sem": 0.04523370562001554, + "df": 106, + "critical": 1.9828, + "moe": 0.0896893915033668, + "p75": 5, + "p99": 5.799999713897705, + "p995": 6.300000190734863, + "p999": 6.300000190734863, + "sampleCount": 107, + "median": 4.799999713897705 + }, + { + "id": "-1033356040_1_1", + "name": "Onyx.multiSet() - full store (250 reports + 250 txns)", + "rank": 3, + "rme": 3.741092452206312, + "samples": [], + "totalTime": 505.80000019073486, + "min": 13, + "max": 20.299999713897705, + "hz": 69.19731116409977, + "period": 14.451428576878138, + "mean": 14.451428576878138, + "variance": 2.473747802093277, + "sd": 1.57281524728535, + "sem": 0.2658542996290195, + "df": 34, + "critical": 2.0336, + "moe": 0.5406413037255741, + "p75": 14.800000190734863, + "p99": 20.299999713897705, + "p995": 20.299999713897705, + "p999": 20.299999713897705, + "sampleCount": 35, + "median": 13.900000095367432 + }, + { + "id": "-1033356040_1_2", + "name": "Onyx.setCollection() - 250 reports", + "rank": 2, + "rme": 24.049421818117846, + "samples": [], + "totalTime": 501.90000009536743, + "min": 0.8999996185302734, + "max": 65, + "hz": 167.36401670460037, + "period": 5.975000001135326, + "mean": 5.975000001135326, + "variance": 43.838042186886454, + "sd": 6.621030296478521, + "sem": 0.722413631243065, + "df": 83, + "critical": 1.9891, + "moe": 1.4369529539055808, + "p75": 6, + "p99": 65, + "p995": 65, + "p999": 65, + "sampleCount": 84, + "median": 5.400000095367432 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (heavy (1000 reports, 1000 txns))", + "benchmarks": [ + { + "id": "-1033356040_2_0", + "name": "Onyx.set() - 1000 reports individually", + "rank": 1, + "rme": 4.004305898951129, + "samples": [], + "totalTime": 504.19999980926514, + "min": 5.199999809265137, + "max": 11.900000095367432, + "hz": 166.60055539820812, + "period": 6.002380950110299, + "mean": 6.002380950110299, + "variance": 1.2265002903197229, + "sd": 1.1074747357478287, + "sem": 0.12083540016227719, + "df": 83, + "critical": 1.9891, + "moe": 0.24035369446278557, + "p75": 6, + "p99": 11.900000095367432, + "p995": 11.900000095367432, + "p999": 11.900000095367432, + "sampleCount": 84, + "median": 5.800000190734863 + }, + { + "id": "-1033356040_2_1", + "name": "Onyx.multiSet() - full store (1000 reports + 1000 txns)", + "rank": 3, + "rme": 7.995059327038918, + "samples": [], + "totalTime": 551.6999998092651, + "min": 51, + "max": 72, + "hz": 18.12579300971039, + "period": 55.16999998092651, + "mean": 55.16999998092651, + "variance": 38.024555677202024, + "sd": 6.166405409734429, + "sem": 1.9499886070744625, + "df": 9, + "critical": 2.262, + "moe": 4.4108742292024345, + "p75": 55.09999990463257, + "p99": 72, + "p995": 72, + "p999": 72, + "sampleCount": 10, + "median": 53.40000009536743 + }, + { + "id": "-1033356040_2_2", + "name": "Onyx.setCollection() - 1000 reports", + "rank": 2, + "rme": 8.523838873114142, + "samples": [], + "totalTime": 507.1000003814697, + "min": 4.199999809265137, + "max": 25.300000190734863, + "hz": 108.45986976656646, + "period": 9.220000006935813, + "mean": 9.220000006935813, + "variance": 8.446814840316812, + "sd": 2.906340454990917, + "sem": 0.39189086700524656, + "df": 54, + "critical": 2.0054, + "moe": 0.7858979446923214, + "p75": 9.400000095367432, + "p99": 25.300000190734863, + "p995": 25.300000190734863, + "p999": 25.300000190734863, + "sampleCount": 55, + "median": 8.800000190734863 + } + ] + }, + { + "fullName": "benchmarks/set.bench.ts > set (extreme (5000 reports, 5000 txns))", + "benchmarks": [ + { + "id": "-1033356040_3_0", + "name": "Onyx.set() - 5000 reports individually", + "rank": 1, + "rme": 14.157436787721728, + "samples": [], + "totalTime": 504.59999990463257, + "min": 28.59999990463257, + "max": 65.7000002861023, + "hz": 27.74474832074107, + "period": 36.042857136045185, + "mean": 36.042857136045185, + "variance": 78.13186960849136, + "sd": 8.839223360029509, + "sem": 2.3623818127427993, + "df": 13, + "critical": 2.16, + "moe": 5.102744715524447, + "p75": 34.5, + "p99": 65.7000002861023, + "p995": 65.7000002861023, + "p999": 65.7000002861023, + "sampleCount": 14, + "median": 33.94999980926514 + }, + { + "id": "-1033356040_3_1", + "name": "Onyx.multiSet() - full store (5000 reports + 5000 txns)", + "rank": 3, + "rme": 16.09077848820552, + "samples": [], + "totalTime": 2488.8999996185303, + "min": 214.09999990463257, + "max": 401.69999980926514, + "hz": 4.01783920669078, + "period": 248.88999996185302, + "mean": 248.88999996185302, + "variance": 3134.6121060409546, + "sd": 55.987606718281455, + "sem": 17.70483579715145, + "df": 9, + "critical": 2.262, + "moe": 40.04833857315658, + "p75": 248.2999997138977, + "p99": 401.69999980926514, + "p995": 401.69999980926514, + "p999": 401.69999980926514, + "sampleCount": 10, + "median": 230.65000009536743 + }, + { + "id": "-1033356040_3_2", + "name": "Onyx.setCollection() - 5000 reports", + "rank": 2, + "rme": 176.5220959803493, + "samples": [], + "totalTime": 1887.0999999046326, + "min": 35.39999961853027, + "max": 1513.9000000953674, + "hz": 5.299136241060551, + "period": 188.70999999046325, + "mean": 188.70999999046325, + "variance": 216871.6476988057, + "sd": 465.6948010218771, + "sem": 147.26562657280402, + "df": 9, + "critical": 2.262, + "moe": 333.1148473076827, + "p75": 48.799999713897705, + "p99": 1513.9000000953674, + "p995": 1513.9000000953674, + "p999": 1513.9000000953674, + "sampleCount": 10, + "median": 38.85000014305115 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/benchmarks/clear.bench.ts b/benchmarks/clear.bench.ts new file mode 100644 index 000000000..3eb6e1b1b --- /dev/null +++ b/benchmarks/clear.bench.ts @@ -0,0 +1,35 @@ +/** + * Benchmarks for Onyx.clear() at each data tier. + * + * Measures how long it takes to clear the entire store + * (both in-memory cache and IndexedDB) at various scales. + */ + +import {bench, describe, beforeAll} from 'vitest'; +import Onyx from '../lib'; +import {generateFullStore, DATA_TIERS} from './dataGenerators'; +import {initOnyx, seedStore, ALL_TIERS, tierLabel} from './setup'; + +beforeAll(async () => { + await initOnyx(); +}); + +for (const tier of ALL_TIERS) { + const label = tierLabel(tier); + const cfg = DATA_TIERS[tier]; + + describe(`clear (${label})`, () => { + bench( + `Onyx.clear() - ${cfg.reports} reports + ${cfg.transactions} txns`, + async () => { + await Onyx.clear(); + }, + { + setup: async () => { + const store = generateFullStore(tier); + await seedStore(store); + }, + }, + ); + }); +} diff --git a/benchmarks/connect.bench.ts b/benchmarks/connect.bench.ts new file mode 100644 index 000000000..b54b39b40 --- /dev/null +++ b/benchmarks/connect.bench.ts @@ -0,0 +1,131 @@ +/** + * Benchmarks for Onyx.connect() subscriber registration + * and subscriber notification throughput. + */ + +import {bench, describe, beforeAll, afterEach} from 'vitest'; +import Onyx from '../lib'; +import {ONYXKEYS, generateFullStore, DATA_TIERS} from './dataGenerators'; +import type {GeneratedStore} from './dataGenerators'; +import {initOnyx, seedStore, clearStore, ALL_TIERS, tierLabel} from './setup'; + +beforeAll(async () => { + await initOnyx(); +}); + +afterEach(async () => { + await clearStore(); +}); + +for (const tier of ALL_TIERS) { + const label = tierLabel(tier); + const cfg = DATA_TIERS[tier]; + + describe(`connect (${label})`, () => { + let store: GeneratedStore; + + bench( + `Onyx.connect() - register ${cfg.reports} individual key subscribers`, + async () => { + const connections: Array> = []; + for (const reportID of store.meta.reportIDs) { + const connection = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + callback: () => {}, + }); + connections.push(connection); + } + // Disconnect all + for (const connection of connections) { + Onyx.disconnect(connection); + } + }, + { + setup: async () => { + store = generateFullStore(tier); + await seedStore(store); + }, + teardown: async () => { + await clearStore(); + }, + }, + ); + + bench( + `Onyx.connect() - collection subscriber for ${cfg.reports} reports`, + async () => { + const connection = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + callback: () => {}, + waitForCollectionCallback: true, + }); + // Give it a moment to fire the initial callback, then disconnect + await new Promise((resolve) => setTimeout(resolve, 0)); + Onyx.disconnect(connection); + }, + { + setup: async () => { + store = generateFullStore(tier); + await seedStore(store); + }, + teardown: async () => { + await clearStore(); + }, + }, + ); + + bench( + `Notification throughput - write with ${Math.min(cfg.reports, 100)} active subscribers`, + async () => { + // Register subscribers + const subscriberCount = Math.min(cfg.reports, 100); + const connections: Array> = []; + let callbackCount = 0; + for (let i = 0; i < subscriberCount; i++) { + const reportID = store.meta.reportIDs[i]; + connections.push( + Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + callback: () => { + callbackCount++; + }, + }), + ); + } + + // Wait for initial callbacks to settle + await new Promise((resolve) => setTimeout(resolve, 50)); + callbackCount = 0; + + // Now trigger updates to all subscribed keys + const promises: Array> = []; + for (let i = 0; i < subscriberCount; i++) { + const reportID = store.meta.reportIDs[i]; + promises.push( + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { + lastMessageText: `Notification bench ${Date.now()}`, + }), + ); + } + await Promise.all(promises); + + // Wait for all notifications to fire + await new Promise((resolve) => setTimeout(resolve, 50)); + + // Disconnect all + for (const connection of connections) { + Onyx.disconnect(connection); + } + }, + { + setup: async () => { + store = generateFullStore(tier); + await seedStore(store); + }, + teardown: async () => { + await clearStore(); + }, + }, + ); + }); +} diff --git a/benchmarks/dataGenerators.ts b/benchmarks/dataGenerators.ts new file mode 100644 index 000000000..0aacbd81b --- /dev/null +++ b/benchmarks/dataGenerators.ts @@ -0,0 +1,567 @@ +/** + * Data generators for Onyx benchmarks. + * + * Produces production-realistic mock data modeled after Expensify App's ONYXKEYS, + * without importing from App to avoid pulling in the entire dependency tree. + * Key strings are replicated verbatim so the shape of the Onyx store matches production. + */ + +// --------------------------------------------------------------------------- +// ONYXKEYS (simplified mirror of App/src/ONYXKEYS.ts) +// --------------------------------------------------------------------------- + +const ONYXKEYS = { + // Scalar keys + ACCOUNT: 'account', + ACCOUNT_MANAGER_REPORT_ID: 'accountManagerReportID', + ACTIVE_CLIENTS: 'activeClients', + DEVICE_ID: 'deviceID', + IS_SIDEBAR_LOADED: 'isSidebarLoaded', + IS_SEARCHING_FOR_REPORTS: 'isSearchingForReports', + PERSISTED_REQUESTS: 'networkRequestQueue', + PERSISTED_ONGOING_REQUESTS: 'networkOngoingRequestQueue', + CURRENT_DATE: 'currentDate', + CREDENTIALS: 'credentials', + STASHED_CREDENTIALS: 'stashedCredentials', + MODAL: 'modal', + NETWORK: 'network', + PERSONAL_DETAILS_LIST: 'personalDetailsList', + PRIVATE_PERSONAL_DETAILS: 'private_personalDetails', + PERSONAL_DETAILS_METADATA: 'personalDetailsMetadata', + SESSION: 'session', + STASHED_SESSION: 'stashedSession', + BETAS: 'betas', + CURRENCY_LIST: 'currencyList', + LOGIN_LIST: 'loginList', + USER_WALLET: 'userWallet', + BANK_ACCOUNT_LIST: 'bankAccountList', + FUND_LIST: 'fundList', + CARD_LIST: 'cardList', + IS_LOADING_APP: 'isLoadingApp', + HAS_LOADED_APP: 'hasLoadedApp', + COUNTRY_CODE: 'countryCode', + COUNTRY: 'country', + PLAID_DATA: 'plaidData', + PREFERRED_THEME: 'nvp_preferredTheme', + NVP_PRIORITY_MODE: 'nvp_priorityMode', + NVP_PREFERRED_LOCALE: 'nvp_preferredLocale', + NVP_ONBOARDING: 'nvp_onboarding', + NVP_QUICK_ACTION_GLOBAL_CREATE: 'nvp_quickActionGlobalCreate', + NVP_TRAVEL_SETTINGS: 'nvp_travelSettings', + PREFERRED_EMOJI_SKIN_TONE: 'nvp_expensify_preferredEmojiSkinTone', + FREQUENTLY_USED_EMOJIS: 'nvp_expensify_frequentlyUsedEmojis', + SAVED_SEARCHES: 'nvp_savedSearches', + RECENT_SEARCHES: 'nvp_recentSearches', + ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT: 'OnyxUpdatesLastUpdateIDAppliedToClient', + LAST_VISITED_PATH: 'lastVisitedPath', + RECENTLY_USED_REPORT_FIELDS: 'recentlyUsedReportFields', + CONCIERGE_REPORT_ID: 'conciergeReportID', + SELF_DM_REPORT_ID: 'selfDMReportID', + MAPBOX_ACCESS_TOKEN: 'mapboxAccessToken', + LAST_ACCESSED_WORKSPACE_POLICY_ID: 'lastAccessedWorkspacePolicyID', + IS_LOADING_REPORT_DATA: 'isLoadingReportData', + WALLET_TRANSFER: 'walletTransfer', + CUSTOM_STATUS_DRAFT: 'customStatusDraft', + + // Collection keys + COLLECTION: { + REPORT: 'report_', + REPORT_ACTIONS: 'reportActions_', + REPORT_METADATA: 'reportMetadata_', + REPORT_DRAFT_COMMENT: 'reportDraftComment_', + REPORT_IS_COMPOSER_FULL_SIZE: 'reportIsComposerFullSize_', + REPORT_USER_IS_TYPING: 'reportUserIsTyping_', + REPORT_NAME_VALUE_PAIRS: 'reportNameValuePairs_', + POLICY: 'policy_', + POLICY_DRAFTS: 'policyDrafts_', + POLICY_CATEGORIES: 'policyCategories_', + POLICY_TAGS: 'policyTags_', + POLICY_RECENTLY_USED_CATEGORIES: 'policyRecentlyUsedCategories_', + POLICY_RECENTLY_USED_TAGS: 'nvp_recentlyUsedTags_', + POLICY_CONNECTION_SYNC_PROGRESS: 'policyConnectionSyncProgress_', + TRANSACTION: 'transactions_', + TRANSACTION_VIOLATIONS: 'transactionViolations_', + TRANSACTION_DRAFT: 'transactionsDraft_', + TRANSACTION_BACKUP: 'transactionsBackup_', + SECURITY_GROUP: 'securityGroup_', + DOWNLOAD: 'download_', + DOMAIN: 'domain_', + NEXT_STEP: 'reportNextStep_', + SNAPSHOT: 'snapshot_', + WORKSPACE_CARDS_LIST: 'cards_', + REPORT_ACTIONS_DRAFTS: 'reportActionsDrafts_', + REPORT_ACTIONS_PAGES: 'reportActionsPages_', + REPORT_ACTIONS_REACTIONS: 'reportActionsReactions_', + REPORT_VIOLATIONS: 'reportViolations_', + SELECTED_TAB: 'selectedTab_', + }, +} as const; + +export {ONYXKEYS}; + +// --------------------------------------------------------------------------- +// Data tiers +// --------------------------------------------------------------------------- + +export type DataTierName = 'small' | 'modest' | 'heavy' | 'extreme'; + +export interface DataTierConfig { + reports: number; + reportActions: number; + transactions: number; + policies: number; + personalDetails: number; +} + +export const DATA_TIERS: Record = { + small: {reports: 50, reportActions: 500, transactions: 50, policies: 1, personalDetails: 20}, + modest: {reports: 250, reportActions: 2500, transactions: 250, policies: 3, personalDetails: 100}, + heavy: {reports: 1000, reportActions: 10000, transactions: 1000, policies: 10, personalDetails: 500}, + extreme: {reports: 5000, reportActions: 50000, transactions: 5000, policies: 25, personalDetails: 2000}, +}; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +let _counter = 0; +function uid(): string { + return String(++_counter); +} + +function randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function randomChoice(arr: readonly T[]): T { + return arr[Math.floor(Math.random() * arr.length)]; +} + +function isoDate(daysAgo = 0): string { + const d = new Date(); + d.setDate(d.getDate() - daysAgo); + return d.toISOString().replace('T', ' ').slice(0, 23); +} + +const MERCHANTS = ['Uber', 'Starbucks', 'Amazon', 'Delta Airlines', 'Marriott', 'WeWork', 'Whole Foods', 'Shell Gas', 'FedEx', 'Apple Store']; +const CURRENCIES = ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'JPY']; +const FIRST_NAMES = ['Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank', 'Grace', 'Heidi', 'Ivan', 'Judy']; +const LAST_NAMES = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez']; +const REPORT_TYPES = ['chat', 'expense', 'iou', 'task']; +const ACTION_NAMES = ['ADDCOMMENT', 'IOU', 'CREATED', 'CLOSED', 'REPORTPREVIEW', 'MARKEDREIMBURSED', 'MODIFIEDEXPENSE']; + +// --------------------------------------------------------------------------- +// Entity generators +// --------------------------------------------------------------------------- + +export interface MockReport { + reportID: string; + reportName: string; + type: string; + stateNum: number; + statusNum: number; + ownerAccountID: number; + managerID: number; + currency: string; + total: number; + nonReimbursableTotal: number; + lastVisibleActionCreated: string; + lastReadTime: string; + lastMessageText: string; + participantAccountIDs: number[]; + participants: Record; + isPinned: boolean; + chatType: string; + policyID: string; + isOwnPolicyExpenseChat: boolean; + hasOutstandingChildRequest: boolean; + description: string; +} + +export function generateReport(id: number, policyID: string): MockReport { + const reportID = String(id); + const ownerAccountID = randomInt(1, 200); + const participantCount = randomInt(1, 5); + const participantAccountIDs = Array.from({length: participantCount}, (_, i) => ownerAccountID + i + 1); + const participants: Record = {}; + for (const pid of participantAccountIDs) { + participants[String(pid)] = {notificationPreference: 'always'}; + } + + return { + reportID, + reportName: `Report #${reportID}`, + type: randomChoice(REPORT_TYPES), + stateNum: randomInt(0, 2), + statusNum: randomInt(0, 4), + ownerAccountID, + managerID: randomInt(1, 200), + currency: randomChoice(CURRENCIES), + total: randomInt(100, 100000), + nonReimbursableTotal: randomInt(0, 5000), + lastVisibleActionCreated: isoDate(randomInt(0, 90)), + lastReadTime: isoDate(randomInt(0, 30)), + lastMessageText: `This is a sample message for report ${reportID}`, + participantAccountIDs, + participants, + isPinned: Math.random() < 0.1, + chatType: 'policyExpenseChat', + policyID, + isOwnPolicyExpenseChat: Math.random() < 0.3, + hasOutstandingChildRequest: Math.random() < 0.2, + description: '', + }; +} + +export interface MockReportAction { + reportActionID: string; + actionName: string; + actorAccountID: number; + created: string; + message: Array<{type: string; html: string; text: string; isEdited: boolean}>; + originalMessage: {html: string; lastModified: string}; + person: Array<{type: string; style: string; text: string}>; + avatar: string; + automatic: boolean; + shouldShow: boolean; + lastModified: string; + pendingAction: string | null; + errors: Record; +} + +export function generateReportAction(index: number): MockReportAction { + const actorAccountID = randomInt(1, 200); + return { + reportActionID: String(index), + actionName: randomChoice(ACTION_NAMES), + actorAccountID, + created: isoDate(randomInt(0, 90)), + message: [ + { + type: 'COMMENT', + html: `

Message body ${index}

`, + text: `Message body ${index}`, + isEdited: Math.random() < 0.1, + }, + ], + originalMessage: { + html: `

Original message ${index}

`, + lastModified: isoDate(randomInt(0, 90)), + }, + person: [{type: 'TEXT', style: 'strong', text: `User ${actorAccountID}`}], + avatar: `https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_${actorAccountID % 8}.png`, + automatic: false, + shouldShow: true, + lastModified: isoDate(randomInt(0, 30)), + pendingAction: null, + errors: {}, + }; +} + +export interface MockTransaction { + transactionID: string; + amount: number; + merchant: string; + currency: string; + created: string; + modifiedCreated: string; + comment: {comment: string}; + category: string; + tag: string; + reportID: string; + receipt: Record; + filename: string; + billable: boolean; + reimbursable: boolean; + pendingAction: string | null; + errors: Record; + cardID: number; + originalAmount: number; + originalCurrency: string; +} + +export function generateTransaction(id: number, reportID: string): MockTransaction { + const currency = randomChoice(CURRENCIES); + const amount = randomInt(100, 50000); + return { + transactionID: String(id), + amount, + merchant: randomChoice(MERCHANTS), + currency, + created: isoDate(randomInt(0, 90)), + modifiedCreated: '', + comment: {comment: `Expense note ${id}`}, + category: randomChoice(['Travel', 'Meals', 'Office', 'Software', 'Transport', '']), + tag: randomChoice(['Project A', 'Project B', 'General', '']), + reportID, + receipt: {}, + filename: '', + billable: Math.random() < 0.3, + reimbursable: Math.random() < 0.7, + pendingAction: null, + errors: {}, + cardID: randomInt(0, 5), + originalAmount: amount, + originalCurrency: currency, + }; +} + +export interface MockPolicy { + id: string; + name: string; + type: string; + role: string; + owner: string; + ownerAccountID: number; + outputCurrency: string; + isPolicyExpenseChatEnabled: boolean; + autoReporting: boolean; + autoReportingFrequency: string; + harvesting: {enabled: boolean}; + defaultBillable: boolean; + disabledFields: {defaultBillable: boolean}; + customUnits: Record; + areCategoriesEnabled: boolean; + areTagsEnabled: boolean; + areDistanceRatesEnabled: boolean; + areWorkflowsEnabled: boolean; + areReportFieldsEnabled: boolean; + areConnectionsEnabled: boolean; + employeeList: Record; +} + +export function generatePolicy(id: number, memberCount = 10): MockPolicy { + const policyID = String(id); + const employeeList: Record = {}; + for (let i = 0; i < memberCount; i++) { + const email = `user${i}@company${id}.com`; + employeeList[email] = {email, role: i === 0 ? 'admin' : 'user'}; + } + return { + id: policyID, + name: `Workspace ${policyID}`, + type: 'team', + role: 'admin', + owner: `admin@company${id}.com`, + ownerAccountID: randomInt(1, 200), + outputCurrency: 'USD', + isPolicyExpenseChatEnabled: true, + autoReporting: true, + autoReportingFrequency: 'immediate', + harvesting: {enabled: true}, + defaultBillable: false, + disabledFields: {defaultBillable: true}, + customUnits: {}, + areCategoriesEnabled: true, + areTagsEnabled: true, + areDistanceRatesEnabled: false, + areWorkflowsEnabled: true, + areReportFieldsEnabled: false, + areConnectionsEnabled: false, + employeeList, + }; +} + +export interface MockPersonalDetails { + accountID: number; + displayName: string; + firstName: string; + lastName: string; + login: string; + avatar: string; + pronouns: string; + timezone: {selected: string; automatic: boolean}; + phoneNumber: string; + validated: boolean; +} + +export function generatePersonalDetails(accountID: number): MockPersonalDetails { + const firstName = randomChoice(FIRST_NAMES); + const lastName = randomChoice(LAST_NAMES); + return { + accountID, + displayName: `${firstName} ${lastName}`, + firstName, + lastName, + login: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${accountID}@example.com`, + avatar: `https://d2k5nsl2zxldvw.cloudfront.net/images/avatars/avatar_${accountID % 8}.png`, + pronouns: '', + timezone: {selected: 'America/New_York', automatic: true}, + phoneNumber: `+1${String(randomInt(2000000000, 9999999999))}`, + validated: true, + }; +} + +// --------------------------------------------------------------------------- +// Scalar keys generator +// --------------------------------------------------------------------------- + +function generateScalarKeys(): Record { + return { + [ONYXKEYS.ACCOUNT]: { + accountID: 12345, + email: 'user@example.com', + validated: true, + requiresTwoFactorAuth: false, + isLoading: false, + }, + [ONYXKEYS.SESSION]: { + authToken: 'mock-auth-token-abcdef123456', + accountID: 12345, + email: 'user@example.com', + encryptedAuthToken: 'mock-encrypted-token', + autoAuthState: 'authenticated', + }, + [ONYXKEYS.CREDENTIALS]: { + login: 'user@example.com', + autoGeneratedLogin: 'user-auto-12345', + autoGeneratedPassword: 'mock-password-hash', + }, + [ONYXKEYS.NETWORK]: {isOffline: false, shouldForceOffline: false}, + [ONYXKEYS.BETAS]: ['all'], + [ONYXKEYS.IS_SIDEBAR_LOADED]: true, + [ONYXKEYS.IS_LOADING_APP]: false, + [ONYXKEYS.HAS_LOADED_APP]: true, + [ONYXKEYS.CURRENT_DATE]: new Date().toISOString().slice(0, 10), + [ONYXKEYS.PREFERRED_THEME]: 'system', + [ONYXKEYS.NVP_PREFERRED_LOCALE]: 'en', + [ONYXKEYS.NVP_PRIORITY_MODE]: 'default', + [ONYXKEYS.COUNTRY_CODE]: 1, + [ONYXKEYS.COUNTRY]: 'US', + [ONYXKEYS.DEVICE_ID]: 'mock-device-id-abcdef', + [ONYXKEYS.ACTIVE_CLIENTS]: ['client-1'], + [ONYXKEYS.MODAL]: {isVisible: false, willAlertModalBecomeVisible: false}, + [ONYXKEYS.PERSISTED_REQUESTS]: [], + [ONYXKEYS.CONCIERGE_REPORT_ID]: '1', + [ONYXKEYS.SELF_DM_REPORT_ID]: '2', + [ONYXKEYS.LAST_VISITED_PATH]: '/home', + [ONYXKEYS.MAPBOX_ACCESS_TOKEN]: {token: 'mock-mapbox-token'}, + [ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE]: 0, + [ONYXKEYS.FREQUENTLY_USED_EMOJIS]: [ + {code: '👍', count: 42, lastUpdatedAt: Date.now()}, + {code: '😂', count: 30, lastUpdatedAt: Date.now()}, + ], + [ONYXKEYS.RECENTLY_USED_REPORT_FIELDS]: {}, + [ONYXKEYS.SAVED_SEARCHES]: {}, + [ONYXKEYS.RECENT_SEARCHES]: [], + [ONYXKEYS.LOGIN_LIST]: { + 'user@example.com': {partnerUserID: 'user@example.com', validatedDate: isoDate(30)}, + }, + [ONYXKEYS.BANK_ACCOUNT_LIST]: {}, + [ONYXKEYS.FUND_LIST]: {}, + [ONYXKEYS.CARD_LIST]: {}, + [ONYXKEYS.USER_WALLET]: {currentBalance: 0}, + [ONYXKEYS.WALLET_TRANSFER]: {}, + [ONYXKEYS.CURRENCY_LIST]: generateCurrencyList(), + [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, + [ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT]: randomInt(100000, 999999), + }; +} + +function generateCurrencyList(): Record { + const list: Record = {}; + const entries: Array<[string, string, string]> = [ + ['USD', '$', 'US Dollar'], + ['EUR', '€', 'Euro'], + ['GBP', '£', 'British Pound'], + ['CAD', 'CA$', 'Canadian Dollar'], + ['AUD', 'A$', 'Australian Dollar'], + ['JPY', '¥', 'Japanese Yen'], + ]; + for (const [iso, symbol, name] of entries) { + list[iso] = {symbol, name, ISO4217: iso}; + } + return list; +} + +// --------------------------------------------------------------------------- +// Full store generator +// --------------------------------------------------------------------------- + +export interface GeneratedStore { + /** Flat key→value map ready to be passed to Onyx.multiSet */ + data: Record; + /** Metadata about what was generated */ + meta: { + tier: DataTierName | 'custom'; + config: DataTierConfig; + reportIDs: string[]; + transactionIDs: string[]; + policyIDs: string[]; + totalKeys: number; + }; +} + +export function generateFullStore(tierOrConfig: DataTierName | DataTierConfig): GeneratedStore { + const tierName: DataTierName | 'custom' = typeof tierOrConfig === 'string' ? tierOrConfig : 'custom'; + const config: DataTierConfig = typeof tierOrConfig === 'string' ? DATA_TIERS[tierOrConfig] : tierOrConfig; + + _counter = 0; // reset uid counter for deterministic IDs + const data: Record = {}; + + // 1. Scalar keys + Object.assign(data, generateScalarKeys()); + + // 2. Policies + const policyIDs: string[] = []; + for (let i = 0; i < config.policies; i++) { + const policy = generatePolicy(i + 1, Math.min(config.personalDetails, 50)); + policyIDs.push(policy.id); + data[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`] = policy; + } + + // 3. Reports + const reportIDs: string[] = []; + for (let i = 0; i < config.reports; i++) { + const policyID = policyIDs[i % policyIDs.length]; + const report = generateReport(i + 1, policyID); + reportIDs.push(report.reportID); + data[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = report; + data[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report.reportID}`] = { + isLoadingInitialReportActions: false, + isLoadingOlderReportActions: false, + isLoadingNewerReportActions: false, + }; + } + + // 4. Report Actions (spread across reports) + for (let i = 0; i < config.reportActions; i++) { + const reportID = reportIDs[i % reportIDs.length]; + const action = generateReportAction(i + 1); + // Report actions are stored as a single object per reportID containing all actions + const key = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; + if (!data[key]) { + data[key] = {}; + } + (data[key] as Record)[action.reportActionID] = action; + } + + // 5. Transactions + const transactionIDs: string[] = []; + for (let i = 0; i < config.transactions; i++) { + const reportID = reportIDs[i % reportIDs.length]; + const txn = generateTransaction(i + 1, reportID); + transactionIDs.push(txn.transactionID); + data[`${ONYXKEYS.COLLECTION.TRANSACTION}${txn.transactionID}`] = txn; + } + + // 6. Personal Details (stored as a single map) + const personalDetailsList: Record = {}; + for (let i = 0; i < config.personalDetails; i++) { + const pd = generatePersonalDetails(i + 1); + personalDetailsList[String(pd.accountID)] = pd; + } + data[ONYXKEYS.PERSONAL_DETAILS_LIST] = personalDetailsList; + + return { + data, + meta: { + tier: tierName, + config, + reportIDs, + transactionIDs, + policyIDs, + totalKeys: Object.keys(data).length, + }, + }; +} diff --git a/benchmarks/init.bench.ts b/benchmarks/init.bench.ts new file mode 100644 index 000000000..901066a5f --- /dev/null +++ b/benchmarks/init.bench.ts @@ -0,0 +1,41 @@ +/** + * Benchmarks for Onyx.init() — cold start and cache hydration. + * + * These measure how long it takes Onyx to initialize and hydrate its + * in-memory cache from IndexedDB with varying store sizes. + */ + +import {bench, describe} from 'vitest'; +import Onyx from '../lib'; +import OnyxUtils from '../lib/OnyxUtils'; +import createDeferredTask from '../lib/createDeferredTask'; +import {ONYXKEYS, generateFullStore, DATA_TIERS} from './dataGenerators'; +import {clearStore, ALL_TIERS, tierLabel} from './setup'; + +for (const tier of ALL_TIERS) { + const label = tierLabel(tier); + const cfg = DATA_TIERS[tier]; + + describe(`init (${label})`, () => { + bench( + `Onyx.init() with ${cfg.reports} initialKeyStates`, + async () => { + const store = generateFullStore(tier); + // Reset the deferred task so init() can resolve fresh + Object.assign(OnyxUtils.getDeferredInitTask(), createDeferredTask()); + Onyx.init({ + keys: ONYXKEYS, + initialKeyStates: store.data, + maxCachedKeysCount: 100000, + enableDevTools: false, + }); + await OnyxUtils.getDeferredInitTask().promise; + }, + { + teardown: async () => { + await Onyx.clear(); + }, + }, + ); + }); +} diff --git a/benchmarks/merge.bench.ts b/benchmarks/merge.bench.ts new file mode 100644 index 000000000..a1f9045c9 --- /dev/null +++ b/benchmarks/merge.bench.ts @@ -0,0 +1,108 @@ +/** + * Benchmarks for Onyx.merge(), Onyx.mergeCollection(), and Onyx.update(). + * + * These benchmarks pre-seed data and then measure the cost of merging + * partial updates into the existing store. + */ + +import {bench, describe, beforeAll, afterEach} from 'vitest'; +import Onyx from '../lib'; +import type {OnyxKey, OnyxUpdate} from '../lib'; +import {ONYXKEYS, generateFullStore, generateReport, DATA_TIERS} from './dataGenerators'; +import type {GeneratedStore} from './dataGenerators'; +import {initOnyx, seedStore, clearStore, ALL_TIERS, tierLabel} from './setup'; + +beforeAll(async () => { + await initOnyx(); +}); + +afterEach(async () => { + await clearStore(); +}); + +for (const tier of ALL_TIERS) { + const label = tierLabel(tier); + const cfg = DATA_TIERS[tier]; + + describe(`merge (${label})`, () => { + let store: GeneratedStore; + + bench( + `Onyx.merge() - partial update ${cfg.reports} reports`, + async () => { + const promises: Array> = []; + for (const reportID of store.meta.reportIDs) { + promises.push( + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { + lastMessageText: `Updated message at ${Date.now()}`, + lastVisibleActionCreated: new Date().toISOString(), + }), + ); + } + await Promise.all(promises); + }, + { + setup: async () => { + store = generateFullStore(tier); + await seedStore(store); + }, + teardown: async () => { + await clearStore(); + }, + }, + ); + + bench( + `Onyx.mergeCollection() - partial update ${cfg.reports} reports`, + async () => { + const updates: Record = {}; + for (const reportID of store.meta.reportIDs) { + updates[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] = { + lastMessageText: `Bulk updated at ${Date.now()}`, + isPinned: true, + }; + } + await Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, updates); + }, + { + setup: async () => { + store = generateFullStore(tier); + await seedStore(store); + }, + teardown: async () => { + await clearStore(); + }, + }, + ); + + bench( + `Onyx.update() - mixed set/merge (${cfg.reports} ops)`, + async () => { + const updates: Array> = store.meta.reportIDs.map((reportID, i) => { + if (i % 2 === 0) { + return { + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + onyxMethod: Onyx.METHOD.SET, + value: generateReport(Number(reportID), '1'), + }; + } + return { + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: {lastMessageText: `Mixed update ${Date.now()}`}, + }; + }); + await Onyx.update(updates); + }, + { + setup: async () => { + store = generateFullStore(tier); + await seedStore(store); + }, + teardown: async () => { + await clearStore(); + }, + }, + ); + }); +} diff --git a/benchmarks/set.bench.ts b/benchmarks/set.bench.ts new file mode 100644 index 000000000..e526662db --- /dev/null +++ b/benchmarks/set.bench.ts @@ -0,0 +1,72 @@ +/** + * Benchmarks for Onyx.set(), Onyx.multiSet(), and Onyx.setCollection(). + * + * Each benchmark is run for every data tier (small → extreme). + */ + +import {bench, describe, beforeAll, afterEach} from 'vitest'; +import Onyx from '../lib'; +import {ONYXKEYS, generateFullStore, generateReport, DATA_TIERS} from './dataGenerators'; +import {initOnyx, clearStore, ALL_TIERS, tierLabel} from './setup'; + +beforeAll(async () => { + await initOnyx(); +}); + +afterEach(async () => { + await clearStore(); +}); + +for (const tier of ALL_TIERS) { + const label = tierLabel(tier); + const cfg = DATA_TIERS[tier]; + + describe(`set (${label})`, () => { + bench( + `Onyx.set() - ${cfg.reports} reports individually`, + async () => { + const promises: Array> = []; + for (let i = 0; i < cfg.reports; i++) { + const report = generateReport(i + 1, '1'); + promises.push(Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report)); + } + await Promise.all(promises); + }, + { + teardown: async () => { + await clearStore(); + }, + }, + ); + + bench( + `Onyx.multiSet() - full store (${cfg.reports} reports + ${cfg.transactions} txns)`, + async () => { + const store = generateFullStore(tier); + await Onyx.multiSet(store.data); + }, + { + teardown: async () => { + await clearStore(); + }, + }, + ); + + bench( + `Onyx.setCollection() - ${cfg.reports} reports`, + async () => { + const collection: Record = {}; + for (let i = 0; i < cfg.reports; i++) { + const report = generateReport(i + 1, '1'); + collection[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = report; + } + await Onyx.setCollection(ONYXKEYS.COLLECTION.REPORT, collection); + }, + { + teardown: async () => { + await clearStore(); + }, + }, + ); + }); +} diff --git a/benchmarks/setup.ts b/benchmarks/setup.ts new file mode 100644 index 000000000..1c6d5416f --- /dev/null +++ b/benchmarks/setup.ts @@ -0,0 +1,69 @@ +/** + * Shared setup / teardown utilities for Onyx benchmarks. + * + * These helpers initialize Onyx with realistic keys, seed IndexedDB with + * generated data, and tear everything down between benchmark iterations. + */ + +import Onyx from '../lib'; +import type {DataTierName, GeneratedStore} from './dataGenerators'; +import {DATA_TIERS, generateFullStore, ONYXKEYS} from './dataGenerators'; + +/** + * Initialize Onyx with the production-like ONYXKEYS. + * Must be called once before benchmarks run. + */ +export async function initOnyx(): Promise { + Onyx.init({ + keys: ONYXKEYS, + maxCachedKeysCount: 100000, + }); + + // Wait for init to settle + await new Promise((resolve) => { + setTimeout(resolve, 100); + }); +} + +/** + * Seed the Onyx store (and underlying IndexedDB) with data from a generated store. + */ +export async function seedStore(store: GeneratedStore): Promise { + await Onyx.multiSet(store.data); +} + +/** + * Clear all Onyx data and the underlying IndexedDB store. + */ +export async function clearStore(): Promise { + await Onyx.clear(); +} + +/** + * Generate data for a tier, seed Onyx, and return the store for later use. + */ +export async function seedTier(tier: DataTierName): Promise { + const store = generateFullStore(tier); + await seedStore(store); + return store; +} + +/** + * Convenience: generate store data without seeding. + */ +export function generateTierData(tier: DataTierName): GeneratedStore { + return generateFullStore(tier); +} + +/** + * Get the human-readable label for a tier (used in benchmark names). + */ +export function tierLabel(tier: DataTierName): string { + const cfg = DATA_TIERS[tier]; + return `${tier} (${cfg.reports} reports, ${cfg.transactions} txns)`; +} + +/** + * All tier names for iteration in benchmarks. + */ +export const ALL_TIERS: DataTierName[] = ['small', 'modest', 'heavy', 'extreme']; diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt new file mode 100644 index 000000000..35d42adab --- /dev/null +++ b/cpp/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.16) +project(OnyxNativeBufferStore LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# --------------------------------------------------------------------------- +# NativeBufferStore (C++ -- thread-safe buffer HybridObject) +# --------------------------------------------------------------------------- +# Pure buffer with std::shared_mutex. No SQLite, no background thread. +# The Worklet Worker Runtime handles persistence via react-native-nitro-sqlite. +add_library(onyx_native_buffer_store STATIC NativeBufferStore.cpp) +target_include_directories(onyx_native_buffer_store PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# --------------------------------------------------------------------------- +# Test harness +# --------------------------------------------------------------------------- +if(BUILD_TESTING) + add_executable(native_buffer_store_test test_native_buffer_store.cpp) + target_link_libraries(native_buffer_store_test PRIVATE onyx_native_buffer_store) +endif() diff --git a/cpp/NativeBufferStore.cpp b/cpp/NativeBufferStore.cpp new file mode 100644 index 000000000..de5a78f77 --- /dev/null +++ b/cpp/NativeBufferStore.cpp @@ -0,0 +1,74 @@ +/** + * NativeBufferStore implementation. + * + * Pure thread-safe buffer -- no background thread, no SQLite. + * Uses std::shared_mutex for reader-writer locking: + * - shared_lock for reads (get, has, size, entries) + * - unique_lock for writes (set, erase, clear, drain) + */ + +#include "NativeBufferStore.h" + +#include + +namespace onyx { + +const NativeBufferEntry* NativeBufferStore::get(const std::string& key) { + std::shared_lock lock(mutex_); + auto it = buffer_.find(key); + if (it == buffer_.end()) { + return nullptr; + } + return &it->second; +} + +void NativeBufferStore::set(const std::string& key, NativeBufferEntry entry) { + std::unique_lock lock(mutex_); + buffer_[key] = std::move(entry); +} + +bool NativeBufferStore::erase(const std::string& key) { + std::unique_lock lock(mutex_); + return buffer_.erase(key) > 0; +} + +bool NativeBufferStore::has(const std::string& key) { + std::shared_lock lock(mutex_); + return buffer_.find(key) != buffer_.end(); +} + +size_t NativeBufferStore::size() { + std::shared_lock lock(mutex_); + return buffer_.size(); +} + +void NativeBufferStore::clear() { + std::unique_lock lock(mutex_); + buffer_.clear(); +} + +std::vector> NativeBufferStore::entries() { + std::shared_lock lock(mutex_); + std::vector> result; + result.reserve(buffer_.size()); + for (const auto& [key, entry] : buffer_) { + result.emplace_back(key, entry); + } + return result; +} + +std::vector> NativeBufferStore::drain() { + std::unique_lock lock(mutex_); + + // Move all entries out of the buffer atomically + std::vector> result; + result.reserve(buffer_.size()); + for (auto& [key, entry] : buffer_) { + result.emplace_back(std::move(key), std::move(entry)); + } + buffer_.clear(); + + return result; +} + +} // namespace onyx diff --git a/cpp/NativeBufferStore.h b/cpp/NativeBufferStore.h new file mode 100644 index 000000000..d80fe04c5 --- /dev/null +++ b/cpp/NativeBufferStore.h @@ -0,0 +1,142 @@ +/** + * NativeBufferStore -- Thread-safe buffer backed by a shared_mutex. + * + * This is the C++ backing store for the native (iOS/Android) BufferStore + * HybridObject. It provides a simple key-value buffer where: + * + * - The main JS thread populates entries via set() + * - The Worklet Worker Runtime drains all entries atomically via drain() + * + * Thread safety: + * - Read methods (get, has, size) use shared_lock (concurrent readers OK) + * - Write methods (set, erase, clear) use unique_lock (exclusive access) + * - drain() uses unique_lock and atomically swaps out the entire buffer + * + * This class stores values as AnyValue-equivalent C++ types (std::string + * for JSON, since the actual AnyMap-to-JSON serialization happens on the + * Worklet Worker Runtime side after draining). The Worklet Worker Runtime + * handles JSON.stringify and calls react-native-nitro-sqlite for persistence. + * + * Future optimization: store AnyMap values directly (no JSON strings) and + * serialize to JSON using Glaze on a pure C++ worker thread, eliminating + * the JS round-trip entirely. + */ + +#pragma once + +#include +#include +#include +#include + +namespace onyx { + +/** + * Entry types matching the TypeScript BufferEntry.entryType. + */ +enum class NativeEntryType { + Set, + Merge, +}; + +/** + * A single buffer entry, storing the key, JSON value, and type. + * + * The value is stored as a JSON string. In the current architecture, + * Nitro's JSIConverter converts JS objects to AnyValue (deep C++ copy) + * on the main thread. The Worklet Worker Runtime then calls drain(), + * converts AnyValue back to JS objects (on the worker thread), and + * JSON.stringifies them for SQLite persistence. + * + * For the C++ buffer, we store pre-serialized JSON strings since the + * BufferStore interface on the TS side handles the AnyMap -> JS + * conversion. This keeps the C++ side simple and focused on + * thread-safe buffering. + */ +struct NativeBufferEntry { + std::string key; + std::string valueJSON; + NativeEntryType entryType; + // replaceNullPatches stored as serialized JSON array string + std::string replaceNullPatchesJSON; +}; + +class NativeBufferStore { +public: + NativeBufferStore() = default; + ~NativeBufferStore() = default; + + // Non-copyable, non-movable + NativeBufferStore(const NativeBufferStore&) = delete; + NativeBufferStore& operator=(const NativeBufferStore&) = delete; + NativeBufferStore(NativeBufferStore&&) = delete; + NativeBufferStore& operator=(NativeBufferStore&&) = delete; + + // ----------------------------------------------------------------------- + // BufferStore interface (called from JS main thread via JSI) + // ----------------------------------------------------------------------- + + /** + * Get a buffer entry by key, or nullptr if not found. + * Thread-safe: acquires shared_lock (allows concurrent readers). + */ + const NativeBufferEntry* get(const std::string& key); + + /** + * Insert or replace a buffer entry. + * Thread-safe: acquires unique_lock (exclusive access). + */ + void set(const std::string& key, NativeBufferEntry entry); + + /** + * Delete a key from the buffer. + * Thread-safe: acquires unique_lock. + */ + bool erase(const std::string& key); + + /** + * Check if a key exists in the buffer. + * Thread-safe: acquires shared_lock. + */ + bool has(const std::string& key); + + /** + * Get the number of pending entries. + * Thread-safe: acquires shared_lock. + */ + size_t size(); + + /** + * Clear all pending entries. + * Thread-safe: acquires unique_lock. + */ + void clear(); + + /** + * Get a snapshot of all entries (for the TS side to iterate). + * Thread-safe: acquires shared_lock. + */ + std::vector> entries(); + + // ----------------------------------------------------------------------- + // Drain (called from Worklet Worker Runtime) + // ----------------------------------------------------------------------- + + /** + * Atomically drain all pending entries from the buffer. + * + * Returns all entries and clears the buffer in a single atomic operation. + * The lock is held only for the duration of a swap -- microseconds. + * The caller (Worklet Worker Runtime) gets sole ownership of the + * returned data and can take its time serializing and persisting. + * + * Thread-safe: acquires unique_lock. + */ + std::vector> drain(); + +private: + mutable std::shared_mutex mutex_; + std::unordered_map buffer_; +}; + +} // namespace onyx diff --git a/cpp/test_native_buffer_store.cpp b/cpp/test_native_buffer_store.cpp new file mode 100644 index 000000000..290a92524 --- /dev/null +++ b/cpp/test_native_buffer_store.cpp @@ -0,0 +1,183 @@ +/** + * Test harness for the simplified NativeBufferStore. + * + * Verifies the thread-safe buffer operations (set, get, erase, clear, + * entries, drain) using std::shared_mutex. No SQLite or background thread. + * + * Run via: + * cd cpp/build && cmake .. -DBUILD_TESTING=ON && make && ./native_buffer_store_test + */ + +#include "NativeBufferStore.h" + +#include +#include +#include + +using namespace onyx; + +static void test_set_and_get() { + std::cout << "test_set_and_get... "; + NativeBufferStore store; + + store.set("key1", {"key1", R"("hello")", NativeEntryType::Set, ""}); + + auto* entry = store.get("key1"); + assert(entry != nullptr); + assert(entry->key == "key1"); + assert(entry->valueJSON == R"("hello")"); + assert(entry->entryType == NativeEntryType::Set); + + assert(store.has("key1")); + assert(!store.has("nonexistent")); + assert(store.size() == 1); + + std::cout << "PASS\n"; +} + +static void test_erase_and_clear() { + std::cout << "test_erase_and_clear... "; + NativeBufferStore store; + + store.set("k1", {"k1", R"(1)", NativeEntryType::Set, ""}); + store.set("k2", {"k2", R"(2)", NativeEntryType::Set, ""}); + store.set("k3", {"k3", R"(3)", NativeEntryType::Set, ""}); + + assert(store.size() == 3); + assert(store.erase("k2")); + assert(store.size() == 2); + assert(!store.has("k2")); + + store.clear(); + assert(store.size() == 0); + + std::cout << "PASS\n"; +} + +static void test_entries() { + std::cout << "test_entries... "; + NativeBufferStore store; + + store.set("a", {"a", R"("va")", NativeEntryType::Set, ""}); + store.set("b", {"b", R"("vb")", NativeEntryType::Merge, ""}); + + auto ents = store.entries(); + assert(ents.size() == 2); + + std::cout << "PASS\n"; +} + +static void test_drain() { + std::cout << "test_drain... "; + NativeBufferStore store; + + store.set("d1", {"d1", R"("v1")", NativeEntryType::Set, ""}); + store.set("d2", {"d2", R"("v2")", NativeEntryType::Merge, ""}); + store.set("d3", {"d3", R"("v3")", NativeEntryType::Set, ""}); + + assert(store.size() == 3); + + // Drain should return all entries and clear the buffer + auto drained = store.drain(); + assert(drained.size() == 3); + assert(store.size() == 0); + + // Verify the drained entries contain expected data + bool found_d1 = false, found_d2 = false, found_d3 = false; + for (const auto& [key, entry] : drained) { + if (key == "d1") { + assert(entry.valueJSON == R"("v1")"); + assert(entry.entryType == NativeEntryType::Set); + found_d1 = true; + } else if (key == "d2") { + assert(entry.valueJSON == R"("v2")"); + assert(entry.entryType == NativeEntryType::Merge); + found_d2 = true; + } else if (key == "d3") { + assert(entry.valueJSON == R"("v3")"); + assert(entry.entryType == NativeEntryType::Set); + found_d3 = true; + } + } + assert(found_d1 && found_d2 && found_d3); + + // Drain again should return empty + auto drained2 = store.drain(); + assert(drained2.empty()); + + std::cout << "PASS\n"; +} + +static void test_drain_during_writes() { + std::cout << "test_drain_during_writes... "; + NativeBufferStore store; + + // Add some entries, drain, then add more and drain again + store.set("before1", {"before1", R"("b1")", NativeEntryType::Set, ""}); + store.set("before2", {"before2", R"("b2")", NativeEntryType::Set, ""}); + + auto first_drain = store.drain(); + assert(first_drain.size() == 2); + assert(store.size() == 0); + + // New entries after drain should be independent + store.set("after1", {"after1", R"("a1")", NativeEntryType::Set, ""}); + + auto second_drain = store.drain(); + assert(second_drain.size() == 1); + assert(second_drain[0].first == "after1"); + assert(store.size() == 0); + + std::cout << "PASS\n"; +} + +static void test_concurrent_set_and_drain() { + std::cout << "test_concurrent_set_and_drain... "; + NativeBufferStore store; + + // Simulate the main thread writing while worker thread drains + std::atomic total_drained{0}; + std::atomic done_writing{false}; + + // Writer thread (simulates main JS thread) + std::thread writer([&store, &done_writing]() { + for (int i = 0; i < 100; ++i) { + std::string key = "key_" + std::to_string(i); + std::string val = "\"value_" + std::to_string(i) + "\""; + store.set(key, {key, val, NativeEntryType::Set, ""}); + } + done_writing = true; + }); + + // Drainer thread (simulates Worklet Worker Runtime) + std::thread drainer([&store, &total_drained, &done_writing]() { + while (!done_writing || store.size() > 0) { + auto drained = store.drain(); + total_drained += static_cast(drained.size()); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + }); + + writer.join(); + drainer.join(); + + // All 100 entries should have been drained total + assert(total_drained == 100); + assert(store.size() == 0); + + std::cout << "PASS\n"; +} + +int main() { + std::cout << "=== NativeBufferStore C++ Tests ===\n"; + + test_set_and_get(); + test_erase_and_clear(); + test_entries(); + test_drain(); + test_drain_during_writes(); + test_concurrent_set_and_drain(); + + std::cout << "\n=== All tests passed! ===\n"; + return 0; +} diff --git a/jestSetup.js b/jestSetup.js index f51f0d54f..0608c04ce 100644 --- a/jestSetup.js +++ b/jestSetup.js @@ -2,10 +2,52 @@ jest.mock('./lib/storage'); jest.mock('./lib/storage/platforms/index.native', () => require('./lib/storage/__mocks__')); jest.mock('./lib/storage/platforms/index', () => require('./lib/storage/__mocks__')); -jest.mock('react-native-device-info', () => ({getFreeDiskStorage: () => {}})); +// Mock react-native-nitro-sqlite for native provider tests jest.mock('react-native-nitro-sqlite', () => ({ - open: () => ({execute: () => {}}), - enableSimpleNullHandling: () => undefined, + open: jest.fn(() => ({ + execute: jest.fn(() => ({rows: {length: 0, item: () => null, _array: []}})), + executeAsync: jest.fn(() => Promise.resolve({rows: {length: 0, item: () => null, _array: []}})), + executeBatch: jest.fn(), + executeBatchAsync: jest.fn(() => Promise.resolve()), + })), + enableSimpleNullHandling: jest.fn(), +})); + +// Mock react-native-device-info for native provider +jest.mock('react-native-device-info', () => ({ + getFreeDiskStorage: jest.fn(() => Promise.resolve(Number.POSITIVE_INFINITY)), +})); + +// Mock react-native-nitro-modules for BufferStore HybridObject +jest.mock('react-native-nitro-modules', () => ({ + NitroModules: { + createHybridObject: jest.fn(() => { + throw new Error('NitroModules not available in test environment'); + }), + }, +})); + +// Mock react-native-worklets-core for NativeFlushWorker +jest.mock('react-native-worklets-core', () => ({ + Worklets: { + createContext: jest.fn(() => ({ + name: 'OnyxFlushWorker', + addDecorator: jest.fn(), + createRunAsync: jest.fn((fn) => (...args) => Promise.resolve(fn(...args))), + runAsync: jest.fn((fn) => Promise.resolve(fn())), + })), + createSharedValue: jest.fn((value) => ({value})), + createRunOnJS: jest.fn((fn) => fn), + runOnJS: jest.fn((fn) => Promise.resolve(fn())), + getCurrentThreadId: jest.fn(() => 0), + defaultContext: { + name: 'default', + addDecorator: jest.fn(), + createRunAsync: jest.fn((fn) => (...args) => Promise.resolve(fn(...args))), + runAsync: jest.fn((fn) => Promise.resolve(fn())), + }, + currentContext: undefined, + }, })); jest.useRealTimers(); diff --git a/lib/index.ts b/lib/index.ts index bb6df0e0c..c6189110c 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -21,7 +21,6 @@ import type { import type {FetchStatus, ResultMetadata, UseOnyxResult, UseOnyxOptions} from './useOnyx'; import type {Connection} from './OnyxConnectionManager'; import useOnyx from './useOnyx'; -import type {OnyxSQLiteKeyValuePair} from './storage/providers/SQLiteProvider'; export default Onyx; export {useOnyx}; @@ -49,5 +48,4 @@ export type { UseOnyxResult, Connection, UseOnyxOptions, - OnyxSQLiteKeyValuePair, }; diff --git a/lib/storage/BufferStore/index.native.ts b/lib/storage/BufferStore/index.native.ts new file mode 100644 index 000000000..af1418597 --- /dev/null +++ b/lib/storage/BufferStore/index.native.ts @@ -0,0 +1,80 @@ +/** + * Native (iOS/Android) BufferStore implementation. + * + * This is a NitroModules HybridObject wrapping a thread-safe C++ buffer + * protected by std::shared_mutex. The HybridObject provides shared memory + * access between the main JS thread and the Worklet Worker Runtime: + * + * Main JS Thread: + * - Onyx.set/merge -> WriteBuffer -> bufferStore.set() -> Nitro fromJSI (deep copy to AnyValue) + * - C++ side acquires unique_lock, inserts entry, releases lock + * + * Worklet Worker Runtime: + * - NativeFlushWorker calls bufferStore.drain() + * - C++ side acquires unique_lock, atomically swaps out all entries, releases lock + * - Nitro toJSI converts AnyValue back to JS objects (on worker thread) + * - Worker does JSON.stringify + nitroSqlite.execute (on worker thread) + * + * When the NitroModules bridge is not available (e.g., in test environments), + * falls back to a plain JS Map implementation. + */ + +import type {NitroModules} from 'react-native-nitro-modules'; +import type {OnyxKey} from '../../types'; +import type {BufferEntry} from '../WriteBuffer'; +import type BufferStoreType from './types'; + +/** + * Creates a native BufferStore backed by a C++ NativeBufferStore HybridObject. + * + * The HybridObject is created via NitroModules.createHybridObject() and + * wraps a std::shared_mutex-protected C++ unordered_map. The drain() method + * atomically returns and clears all pending entries. + * + * When the NitroModules bridge is not available (e.g., in test environments), + * falls back to a plain JS Map implementation. + */ +function createNativeBufferStore(): BufferStoreType { + // Attempt to use the NitroModules HybridObject + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const {NitroModules: NM} = require('react-native-nitro-modules') as {NitroModules: typeof NitroModules}; + + // The HybridObject is generated by nitrogen codegen from the C++ + // NativeBufferStore class. It exposes the same interface as BufferStore. + const nativeStore = NM.createHybridObject('NativeBufferStore'); + + return nativeStore; + } catch { + // NitroModules not available -- fall back to JS Map + // This happens in test environments or when the native module isn't linked + console.warn('[Onyx] NativeBufferStore not available, falling back to JS Map'); + + const map = new Map(); + return { + get(key: OnyxKey): BufferEntry | undefined { + return map.get(key); + }, + set(key: OnyxKey, entry: BufferEntry): void { + map.set(key, entry); + }, + delete(key: OnyxKey): boolean { + return map.delete(key); + }, + has(key: OnyxKey): boolean { + return map.has(key); + }, + get size(): number { + return map.size; + }, + clear(): void { + map.clear(); + }, + entries(): IterableIterator<[OnyxKey, BufferEntry]> { + return map.entries(); + }, + }; + } +} + +export default createNativeBufferStore; diff --git a/lib/storage/BufferStore/index.ts b/lib/storage/BufferStore/index.ts new file mode 100644 index 000000000..5ed4af0ea --- /dev/null +++ b/lib/storage/BufferStore/index.ts @@ -0,0 +1,41 @@ +/** + * Web default BufferStore implementation. + * + * A trivial wrapper around a JS `Map`. This is the + * default backing store for the WriteBuffer on all platforms that don't + * provide a native override (i.e., web). + */ +import type {OnyxKey} from '../../types'; +import type {BufferEntry} from '../WriteBuffer'; +import type BufferStoreType from './types'; + +function createBufferStore(): BufferStoreType { + const map = new Map(); + + return { + get(key: OnyxKey): BufferEntry | undefined { + return map.get(key); + }, + set(key: OnyxKey, entry: BufferEntry): void { + map.set(key, entry); + }, + delete(key: OnyxKey): boolean { + return map.delete(key); + }, + has(key: OnyxKey): boolean { + return map.has(key); + }, + get size(): number { + return map.size; + }, + clear(): void { + map.clear(); + }, + entries(): IterableIterator<[OnyxKey, BufferEntry]> { + return map.entries(); + }, + }; +} + +export default createBufferStore; +export type {BufferStoreType as BufferStore}; diff --git a/lib/storage/BufferStore/types.ts b/lib/storage/BufferStore/types.ts new file mode 100644 index 000000000..4da842dc1 --- /dev/null +++ b/lib/storage/BufferStore/types.ts @@ -0,0 +1,22 @@ +import type {OnyxKey} from '../../types'; +import type {BufferEntry} from '../WriteBuffer'; + +/** + * Interface for the backing data structure of the WriteBuffer. + * + * Platform-specific implementations: + * - `index.ts` (web default): simple JS `Map` wrapper + * - `index.native.ts` (iOS/Android): NitroModules HybridObject with + * mutex-protected shared C++ memory and background flush thread + */ +interface BufferStore { + get(key: OnyxKey): BufferEntry | undefined; + set(key: OnyxKey, entry: BufferEntry): void; + delete(key: OnyxKey): boolean; + has(key: OnyxKey): boolean; + readonly size: number; + clear(): void; + entries(): IterableIterator<[OnyxKey, BufferEntry]>; +} + +export default BufferStore; diff --git a/lib/storage/InstanceSync/index.web.ts b/lib/storage/InstanceSync/index.web.ts index cb1a3c5bb..c59d54fe6 100644 --- a/lib/storage/InstanceSync/index.web.ts +++ b/lib/storage/InstanceSync/index.web.ts @@ -1,59 +1,160 @@ /** - * The InstancesSync object provides data-changed events like the ones that exist - * when using LocalStorage APIs in the browser. These events are great because multiple tabs can listen for when - * data changes and then stay up-to-date with everything happening in Onyx. + * The InstancesSync object provides data-changed events across browser tabs. + * + * This implementation listens on the unified `onyx-sync` BroadcastChannel for + * value-bearing messages from the storage worker. When another tab's worker + * persists changes, it broadcasts the values directly, so this tab can update + * its cache without re-reading from storage. + * + * For merge operations, the raw patch is broadcast and applied against the + * local cache using fastMerge. If the key is not in cache, we fall back to + * reading from the storage provider. + * + * The InstanceSync also retains its sending capabilities (setItem, multiSet, etc.) + * for the IDB fallback path. When the worker handles broadcasting (the normal + * case), these send methods are skipped by storage/index.ts. */ import type {OnyxKey} from '../../types'; +import cache from '../../OnyxCache'; +import utils from '../../utils'; import NoopProvider from '../providers/NoopProvider'; import type {StorageKeyList, OnStorageKeyChanged} from '../providers/types'; import type StorageProvider from '../providers/types'; -const SYNC_ONYX = 'SYNC_ONYX'; +const SYNC_CHANNEL_NAME = 'onyx-sync'; /** - * Raise an event through `localStorage` to let other tabs know a value changed - * @param {String} onyxKey + * Legacy channel for key-only messages from the IDB fallback path. + * Once IDB is moved to a worker, this can be removed. + */ +const LEGACY_CHANNEL_NAME = 'onyx-instance-sync'; + +let syncChannel: BroadcastChannel | null = null; +let legacyChannel: BroadcastChannel | null = null; +let storage: StorageProvider = NoopProvider; + +/** + * Broadcast a single key change to other tabs (legacy IDB fallback path). */ function raiseStorageSyncEvent(onyxKey: OnyxKey) { - global.localStorage.setItem(SYNC_ONYX, onyxKey); - global.localStorage.removeItem(SYNC_ONYX); + legacyChannel?.postMessage({type: 'keyChanged', key: onyxKey}); } +/** + * Broadcast multiple key changes to other tabs in a single message (legacy IDB fallback path). + */ function raiseStorageSyncManyKeysEvent(onyxKeys: StorageKeyList) { - for (const onyxKey of onyxKeys) { - raiseStorageSyncEvent(onyxKey); - } + if (onyxKeys.length === 0) return; + legacyChannel?.postMessage({type: 'keysChanged', keys: onyxKeys}); } -let storage = NoopProvider; - const InstanceSync = { shouldBeUsed: true, + /** - * @param {Function} onStorageKeyChanged Storage synchronization mechanism keeping all opened tabs in sync + * Initialize the BroadcastChannel listeners for cross-tab synchronization. + * + * Two channels are set up: + * 1. `onyx-sync` - Value-bearing messages from the unified worker. This is + * the primary sync path for both SQLite and IDB (since both now run in + * the worker). Messages carry actual values/patches, avoiding re-reads. + * 2. `onyx-instance-sync` - Legacy key-only messages. Retained as fallback + * for any edge cases. Will be removed once fully migrated. + * + * @param onStorageKeyChanged - Callback invoked when another tab changes a key + * @param store - The storage provider to read updated values from (fallback only) */ init: (onStorageKeyChanged: OnStorageKeyChanged, store: StorageProvider) => { storage = store; - // This listener will only be triggered by events coming from other tabs - global.addEventListener('storage', (event) => { - // Ignore events that don't originate from the SYNC_ONYX logic - if (event.key !== SYNC_ONYX || !event.newValue) { - return; + // Close any existing channels before creating new ones + if (syncChannel) { + syncChannel.close(); + } + if (legacyChannel) { + legacyChannel.close(); + } + + // --- Primary channel: value-bearing messages from the worker --- + syncChannel = new BroadcastChannel(SYNC_CHANNEL_NAME); + syncChannel.onmessage = (event: MessageEvent) => { + const data = event.data; + if (!data) return; + + if (data.type === 'set' && Array.isArray(data.pairs)) { + // SET: full values included, no storage reads needed + for (const [key, value] of data.pairs) { + onStorageKeyChanged(key, value); + } + } else if (data.type === 'merge' && Array.isArray(data.pairs)) { + // MERGE: raw patch included, apply fastMerge against cache + for (const [key, patch] of data.pairs) { + const cachedValue = cache.get(key); + if (cachedValue !== undefined) { + // Fast path: merge against cached value + const mergedValue = utils.fastMerge(cachedValue as Record, patch as Record, { + shouldRemoveNestedNulls: true, + objectRemovalMode: 'replace', + }).result; + onStorageKeyChanged(key, mergedValue); + } else { + // Slow path: key not in cache, read from storage then apply merge + storage.getItem(key).then((storedValue) => { + if (storedValue !== null && storedValue !== undefined) { + const mergedValue = utils.fastMerge(storedValue as Record, patch as Record, { + shouldRemoveNestedNulls: true, + objectRemovalMode: 'replace', + }).result; + onStorageKeyChanged(key, mergedValue); + } else { + // No stored value either -- treat the patch as the full value + onStorageKeyChanged(key, patch); + } + }); + } + } + } else if (data.type === 'remove' && Array.isArray(data.keys)) { + // REMOVE: notify with null value + for (const key of data.keys) { + onStorageKeyChanged(key, null); + } + } else if (data.type === 'clear') { + // CLEAR: notify all cached keys with null + const allCachedKeys = cache.getAllKeys(); + for (const key of allCachedKeys) { + onStorageKeyChanged(key, null); + } } + }; - const onyxKey = event.newValue; + // --- Legacy channel: key-only messages (IDB fallback) --- + legacyChannel = new BroadcastChannel(LEGACY_CHANNEL_NAME); + legacyChannel.onmessage = (event: MessageEvent) => { + const data = event.data; + if (!data) return; - storage.getItem(onyxKey).then((value) => onStorageKeyChanged(onyxKey, value)); - }); + if (data.type === 'keyChanged' && data.key) { + storage.getItem(data.key).then((value) => onStorageKeyChanged(data.key, value)); + } else if (data.type === 'keysChanged' && Array.isArray(data.keys)) { + for (const key of data.keys) { + storage.getItem(key).then((value) => onStorageKeyChanged(key, value)); + } + } else if (data.type === 'clear' && Array.isArray(data.keys)) { + for (const key of data.keys) { + storage.getItem(key).then((value) => onStorageKeyChanged(key, value)); + } + } + }; }, + setItem: raiseStorageSyncEvent, removeItem: raiseStorageSyncEvent, removeItems: raiseStorageSyncManyKeysEvent, multiMerge: raiseStorageSyncManyKeysEvent, multiSet: raiseStorageSyncManyKeysEvent, mergeItem: raiseStorageSyncEvent, - clear: (clearImplementation: () => void) => { + + clear: (clearImplementation: () => Promise) => { let allKeys: StorageKeyList; // The keys must be retrieved before storage is cleared or else the list of keys would be empty @@ -64,9 +165,8 @@ const InstanceSync = { }) .then(() => clearImplementation()) .then(() => { - // Now that storage is cleared, the storage sync event can happen which is a more atomic action - // for other browser tabs - raiseStorageSyncManyKeysEvent(allKeys); + // Now that storage is cleared, broadcast the clear event with all affected keys + legacyChannel?.postMessage({type: 'clear', keys: allKeys}); }); }, }; diff --git a/lib/storage/NativeFlushWorker.ts b/lib/storage/NativeFlushWorker.ts new file mode 100644 index 000000000..08619ed94 --- /dev/null +++ b/lib/storage/NativeFlushWorker.ts @@ -0,0 +1,183 @@ +/** + * NativeFlushWorker -- Manages the Worklet Worker Runtime for native persistence. + * + * Creates a background JS thread using react-native-worklets-core's context API. + * The flush worklet periodically: + * 1. Calls bufferStore.drain() on the shared HybridObject (shared memory, no postMessage) + * 2. JSON.stringifies the drained entries (on the worker thread, not main thread) + * 3. Calls react-native-nitro-sqlite sync APIs to persist to SQLite + * + * The main thread only pays the cost of AnyMap conversion (via Nitro's fromJSI) + * when populating the buffer. All serialization and I/O happens on the worker. + * + * Architecture symmetry: This is the native analog of the web's worker.ts + + * WorkerStorageProvider, but uses shared memory instead of postMessage. + */ + +import type {IWorkletContext, IWorkletNativeApi} from 'react-native-worklets-core'; +import type {BufferEntry} from './WriteBuffer'; +import type BufferStore from './BufferStore/types'; + +/** + * Flush interval in milliseconds. The worker thread wakes up at this + * cadence to drain and persist any buffered writes. + */ +const FLUSH_INTERVAL_MS = 200; + +/** + * Creates and starts the native flush worker. + * + * Uses react-native-worklets-core to create a dedicated background context + * ("OnyxFlushWorker") that runs flush worklets. The SQLite provider and + * buffer store are injected into the context as decorators so they're + * accessible inside worklets without closure capturing. + * + * @param bufferStore - The HybridObject-backed BufferStore shared with the main thread + * @returns Object with start(), stop(), flushNow(), and getProvider() + */ +function createNativeFlushWorker(bufferStore: BufferStore) { + let flushInterval: ReturnType | null = null; + let isRunning = false; + let workerContext: IWorkletContext | null = null; + + // Import the native SQLite provider lazily to avoid circular deps + // eslint-disable-next-line @typescript-eslint/no-var-requires + const nativeSQLiteProvider = require('./providers/SQLiteProvider/index.native').default; + + /** + * Perform a single flush cycle: drain the buffer and persist to SQLite. + * + * This is called from the Worklet context (background thread). The + * bufferStore.drain() operation is a shared-memory read (no postMessage), + * and JSON.stringify + SQLite execute happen entirely off the main thread. + */ + function flush(): void { + if (bufferStore.size === 0) { + return; + } + + // Drain all entries from the shared buffer atomically + const entries = Array.from(bufferStore.entries()); + bufferStore.clear(); + + if (entries.length === 0) { + return; + } + + // Separate SET and MERGE entries for the provider + const setPairs: [string, unknown][] = []; + const mergePairs: [string, unknown, unknown][] = []; + + for (const [, entry] of entries) { + const typedEntry = entry as BufferEntry; + if (typedEntry.entryType === 'set') { + setPairs.push([typedEntry.key, typedEntry.value]); + } else { + mergePairs.push([typedEntry.key, typedEntry.value, typedEntry.replaceNullPatches]); + } + } + + // Persist to SQLite using sync APIs (on the worker thread) + try { + if (setPairs.length > 0) { + nativeSQLiteProvider.multiSet(setPairs); + } + if (mergePairs.length > 0) { + nativeSQLiteProvider.multiMerge(mergePairs); + } + } catch (error) { + console.error('[Onyx] NativeFlushWorker: flush error:', error); + } + } + + /** + * Schedule periodic flush on the Worklet context. + * The main thread triggers a runAsync on the worker context at FLUSH_INTERVAL_MS + * cadence. The actual drain + serialize + persist all execute on the worker thread. + */ + function schedulePeriodicFlush(): void { + if (flushInterval !== null) { + return; + } + + if (workerContext) { + // Use the Worklet context to run flush on the background thread. + // createRunAsync memoizes the worklet so repeated calls are efficient. + const runFlush = workerContext.createRunAsync(flush); + flushInterval = setInterval(() => { + runFlush().catch((error) => { + console.error('[Onyx] NativeFlushWorker: scheduled flush error:', error); + }); + }, FLUSH_INTERVAL_MS); + } else { + // Fallback: no Worklet context available (e.g., test environment). + // Run flush directly on the main thread. + flushInterval = setInterval(flush, FLUSH_INTERVAL_MS); + } + } + + return { + /** + * Start the flush worker. Initializes the SQLite provider, creates + * the Worklet context, and begins periodic flushing. + */ + start(): void { + if (isRunning) { + return; + } + + // Initialize the native SQLite provider + nativeSQLiteProvider.init(); + + // Create the Worklet context for background flush + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const {Worklets} = require('react-native-worklets-core') as {Worklets: IWorkletNativeApi}; + workerContext = Worklets.createContext('OnyxFlushWorker'); + } catch { + console.warn('[Onyx] react-native-worklets-core not available, flush will run on main thread'); + workerContext = null; + } + + isRunning = true; + schedulePeriodicFlush(); + }, + + /** + * Stop the flush worker and perform a final flush to ensure all + * pending writes are persisted. + */ + stop(): void { + if (!isRunning) { + return; + } + + isRunning = false; + if (flushInterval !== null) { + clearInterval(flushInterval); + flushInterval = null; + } + + // Final flush to persist any remaining entries + flush(); + }, + + /** + * Force an immediate flush (e.g., on app background/shutdown). + */ + flushNow(): void { + flush(); + }, + + /** + * Get the underlying SQLite provider for read operations. + * Read operations go directly to the provider, bypassing the buffer. + */ + getProvider() { + return nativeSQLiteProvider; + }, + }; +} + +export default createNativeFlushWorker; +export type NativeFlushWorker = ReturnType; diff --git a/lib/storage/WorkerStorageProvider.ts b/lib/storage/WorkerStorageProvider.ts new file mode 100644 index 000000000..05798b284 --- /dev/null +++ b/lib/storage/WorkerStorageProvider.ts @@ -0,0 +1,194 @@ +/** + * Worker Storage Provider + * + * Main-thread proxy that communicates with the storage Web Worker + * (lib/storage/worker.ts). Implements the StorageProvider interface + * so it can be used as a drop-in replacement for any storage backend on web. + * + * The caller chooses the backend at creation time: + * - 'sqlite': @sqlite.org/sqlite-wasm with opfs-sahpool VFS + * - 'idb': IDBKeyValProvider fallback for browsers without OPFS + * + * All database operations are offloaded to the worker. This provider only + * manages the postMessage protocol and Promise resolution. Values pass + * through structured clone (native JS objects), so no JSON.parse is needed + * on the main thread. + */ + +import utils from '../utils'; +import type StorageProvider from './providers/types'; +import type {StorageKeyList, StorageKeyValuePair} from './providers/types'; + +// Message counter for matching responses to requests +let nextMessageId = 0; + +// Promise registry keyed by message ID +const pendingRequests = new Map void; reject: (reason: unknown) => void}>(); + +/** + * Generate a unique message ID for request-response matching. + */ +function generateId(): string { + nextMessageId += 1; + return `msg_${nextMessageId}_${Date.now()}`; +} + +/** + * The worker instance (created during init). + */ +let worker: Worker | null = null; + +/** + * Send a message to the worker and return a Promise that resolves with the result. + */ +function postToWorker(message: Record): Promise { + return new Promise((resolve, reject) => { + if (!worker) { + reject(new Error('Storage worker not initialized')); + return; + } + + const id = generateId(); + pendingRequests.set(id, { + resolve: resolve as (value: unknown) => void, + reject, + }); + + worker.postMessage({...message, id}); + }); +} + +/** + * Handle messages from the worker. Matches response to pending request by ID. + */ +function handleWorkerMessage(event: MessageEvent): void { + const {type, id, data, error} = event.data; + if (type !== 'result') return; + + const pending = pendingRequests.get(id); + if (!pending) return; + pendingRequests.delete(id); + + if (error) { + pending.reject(new Error(error)); + } else { + pending.resolve(data); + } +} + +/** + * Create a WorkerStorageProvider that delegates all operations to the + * storage web worker. The caller specifies the backend to use: + * - 'sqlite': @sqlite.org/sqlite-wasm with opfs-sahpool VFS (preferred) + * - 'idb': IDBKeyValProvider fallback + * + * @param backend - The storage backend for the worker to use + */ +function createWorkerStorageProvider(backend: 'sqlite' | 'idb'): StorageProvider { + const provider: StorageProvider = { + store: null, + + /** + * The name of the provider that can be printed to the logs + */ + name: `WorkerStorageProvider (${backend})`, + + /** + * Initializes the storage provider by spawning the web worker. + * The worker is told which backend to use via the init message. + * + * Returns a Promise that resolves once the worker has finished + * initializing its storage backend (SQLite or IDB). This ensures + * that callers waiting on Storage.init() don't proceed until the + * worker is actually ready to accept data operations. + */ + init() { + // Create the worker. The bundler (webpack/vite) will handle the URL resolution. + worker = new Worker(new URL('./worker.ts', import.meta.url), {type: 'module'}); + worker.onmessage = handleWorkerMessage; + worker.onerror = (error) => { + console.error('Storage worker error:', error); + }; + + provider.store = worker; + + // Send init message with the chosen backend and return the Promise + // so that Storage.init() can await worker readiness. + return postToWorker({type: 'init', backend}).catch((error) => { + console.error('Failed to initialize storage worker:', error); + }); + }, + + getItem(key) { + return postToWorker({type: 'getItem', key}).then((result) => { + if (result === null || result === undefined) { + return null; + } + return result; + }); + }, + + multiGet(keys) { + return postToWorker({type: 'multiGet', keys}).then((results) => { + return results ?? []; + }); + }, + + setItem(key, value) { + return postToWorker({type: 'setItem', key, value}); + }, + + multiSet(pairs) { + if (utils.isEmptyObject(pairs)) { + return Promise.resolve(); + } + const normalized = pairs.map(([key, value]) => [key, value === undefined ? null : value]); + return postToWorker({type: 'multiSet', pairs: normalized}); + }, + + multiMerge(pairs) { + const nonNullishPairs = pairs.filter((pair) => pair[1] !== undefined); + const prepared = nonNullishPairs.map(([key, value, replaceNullPatches]) => { + return [key, value, replaceNullPatches] as [string, unknown, unknown[] | undefined]; + }); + return postToWorker({type: 'multiMerge', pairs: prepared}); + }, + + mergeItem(key, change, replaceNullPatches) { + return provider.multiMerge([[key, change, replaceNullPatches]]); + }, + + getAllKeys() { + return postToWorker({type: 'getAllKeys'}).then((keys) => (keys ?? []) as StorageKeyList); + }, + + removeItem(key) { + return postToWorker({type: 'removeItem', key}); + }, + + removeItems(keys) { + return postToWorker({type: 'removeItems', keys}); + }, + + clear() { + return postToWorker({type: 'clear'}); + }, + + getDatabaseSize() { + return postToWorker<{bytesUsed: number; bytesRemaining: number}>({type: 'getDatabaseSize'}).then((size) => { + // Supplement with StorageManager if available for more accurate remaining space + if (typeof navigator !== 'undefined' && navigator.storage && navigator.storage.estimate) { + return navigator.storage.estimate().then((estimate) => ({ + bytesUsed: size.bytesUsed, + bytesRemaining: (estimate.quota ?? 0) - (estimate.usage ?? 0), + })); + } + return size; + }); + }, + }; + + return provider; +} + +export default createWorkerStorageProvider; diff --git a/lib/storage/WriteBuffer.ts b/lib/storage/WriteBuffer.ts new file mode 100644 index 000000000..0035f082d --- /dev/null +++ b/lib/storage/WriteBuffer.ts @@ -0,0 +1,353 @@ +/** + * WriteBuffer implements a patch-staging layer for storage operations. + * + * It tracks two types of pending entries: + * - SET entries: full values from set()/multiSet(), flushed via multiSet + * - MERGE entries: accumulated patch deltas from merge operations, flushed via + * multiMerge (preserving JSON_PATCH efficiency on SQLite) + * + * Multiple writes to the same key are coalesced: successive sets replace the + * value, successive merges accumulate patches, and a set after a merge discards + * the pending patch. A merge after a set applies the patch to the full value + * in-memory (unavoidable since the set hasn't been persisted yet). + * + * The backing data structure is pluggable via the `BufferStore` interface: + * - Web: JS `Map` (BufferStore/index.ts) + * - Native: NitroModules HybridObject with shared C++ memory + * (BufferStore/index.native.ts) + * + * Flush scheduling is also pluggable. On web, `requestIdleCallback` is used. + * On native, the background C++ thread handles flushing, so the scheduler is + * a no-op. + */ + +import type {OnyxKey, OnyxValue} from '../types'; +import type {FastMergeReplaceNullPatch} from '../utils'; +import utils from '../utils'; +import type {StorageKeyValuePair} from './providers/types'; +import type BufferStore from './BufferStore/types'; + +type EntryType = 'set' | 'merge'; + +type BufferEntry = { + key: OnyxKey; + value: OnyxValue; + entryType: EntryType; + replaceNullPatches?: FastMergeReplaceNullPatch[]; +}; + +/** Flush handlers for the two entry types. */ +type FlushHandlers = { + multiSet: (pairs: StorageKeyValuePair[]) => Promise; + multiMerge: (pairs: StorageKeyValuePair[]) => Promise; +}; + +/** + * A function that schedules a flush. The implementation is platform-specific: + * - Web: schedules via requestIdleCallback with a timeout + * - Native: no-op (the native BufferStore's background thread handles it) + * + * Returns a handle that can be passed to `cancelFlush`, or null if no + * cancellation is needed. + */ +type FlushScheduler = (doFlush: () => void) => number | null; + +/** + * A function that cancels a previously scheduled flush. + */ +type CancelFlush = (handle: number) => void; + +/** + * Maximum delay before a scheduled flush is forced, in milliseconds. + * + * Under normal conditions, requestIdleCallback fires during the next idle + * period (often within a few ms). This timeout is a safety net: if the + * browser stays busy for longer than FLUSH_TIMEOUT_MS, the flush is forced. + * + * 200ms lets typical write bursts (10-50ms) fully coalesce before flushing, + * while still being well under perceptible delay. The WriteBuffer's + * read-through ensures in-memory consistency regardless of flush timing. + */ +const FLUSH_TIMEOUT_MS = 200; + +/** Default web flush scheduler using requestIdleCallback with setTimeout fallback. */ +function defaultScheduleFlush(doFlush: () => void): number | null { + if (typeof requestIdleCallback === 'function') { + return requestIdleCallback(doFlush, {timeout: FLUSH_TIMEOUT_MS}) as unknown as number; + } + return setTimeout(doFlush, FLUSH_TIMEOUT_MS) as unknown as number; +} + +/** Default web cancel flush using cancelIdleCallback with clearTimeout fallback. */ +function defaultCancelFlush(handle: number): void { + if (typeof cancelIdleCallback === 'function') { + cancelIdleCallback(handle); + } else { + clearTimeout(handle); + } +} + +type WriteBufferConfig = { + handlers: FlushHandlers; + store: BufferStore; + scheduleFlush?: FlushScheduler; + cancelFlush?: CancelFlush; +}; + +class WriteBuffer { + /** The pluggable backing store for pending buffer entries. */ + private store: BufferStore; + + /** Handle returned by the scheduled flush, used for cancellation. */ + private flushHandle: number | null = null; + + /** Whether a flush is currently in progress. */ + private isFlushing = false; + + /** The handlers called on flush for each entry type. */ + private readonly handlers: FlushHandlers; + + /** Platform-specific flush scheduler. */ + private readonly scheduleFlushFn: FlushScheduler; + + /** Platform-specific flush cancellation. */ + private readonly cancelFlushFn: CancelFlush; + + constructor(config: WriteBufferConfig) { + this.handlers = config.handlers; + this.store = config.store; + this.scheduleFlushFn = config.scheduleFlush ?? defaultScheduleFlush; + this.cancelFlushFn = config.cancelFlush ?? defaultCancelFlush; + } + + /** + * Stage a full value for a key (SET entry). If the key had a pending MERGE, + * the set replaces it entirely. A flush is scheduled if not already pending. + */ + set(key: OnyxKey, value: OnyxValue): void { + this.store.set(key, {key, value, entryType: 'set'}); + this.scheduleFlush(); + } + + /** + * Stage full values for multiple keys (all as SET entries). + */ + setMany(pairs: StorageKeyValuePair[]): void { + for (const [key, value] of pairs) { + this.store.set(key, {key, value, entryType: 'set'}); + } + this.scheduleFlush(); + } + + /** + * Stage a merge patch for a key (MERGE entry). Interaction with existing entries: + * - No existing entry: create a MERGE entry with just the patch + * - Existing SET entry: apply patch to the full value in-memory, keep as SET + * - Existing MERGE entry: merge patches together, keep as MERGE + */ + merge(key: OnyxKey, patch: OnyxValue, replaceNullPatches?: FastMergeReplaceNullPatch[]): void { + const existing = this.store.get(key); + + if (!existing) { + // No pending write -- stage as a MERGE entry (just the patch) + this.store.set(key, {key, value: patch, entryType: 'merge', replaceNullPatches}); + } else if (existing.entryType === 'set') { + // Pending SET -- apply patch to the full value, stay as SET + const {result: merged} = utils.fastMerge(existing.value as Record, patch as Record, { + shouldRemoveNestedNulls: true, + objectRemovalMode: 'replace', + }); + this.store.set(key, {key, value: merged as OnyxValue, entryType: 'set'}); + } else { + // Pending MERGE -- merge patches together, stay as MERGE + const {result: mergedPatch} = utils.fastMerge(existing.value as Record, patch as Record, { + shouldRemoveNestedNulls: false, // preserve nulls -- provider handles them + }); + const combinedPatches = [...(existing.replaceNullPatches ?? []), ...(replaceNullPatches ?? [])]; + this.store.set(key, { + key, + value: mergedPatch as OnyxValue, + entryType: 'merge', + replaceNullPatches: combinedPatches.length > 0 ? combinedPatches : undefined, + }); + } + + this.scheduleFlush(); + } + + /** + * Remove a key from the write buffer. This is used when a key is being + * removed from storage entirely (not just set to null). + */ + remove(key: OnyxKey): void { + this.store.delete(key); + } + + /** + * Remove multiple keys from the write buffer. + */ + removeMany(keys: OnyxKey[]): void { + for (const key of keys) { + this.store.delete(key); + } + } + + /** + * Read-through for SET entries only. Returns the pending full value if the + * key has a SET entry, or undefined otherwise. MERGE entries are not served + * because they contain only a patch, not a complete value -- the caller + * should fall through to the provider for those. + */ + get(key: OnyxKey): OnyxValue | undefined { + const entry = this.store.get(key); + if (entry?.entryType === 'set') { + return entry.value; + } + return undefined; + } + + /** + * Check whether the given key has a pending SET entry (suitable for + * read-through). Returns false for MERGE entries since those only + * contain a patch, not a complete value. + */ + has(key: OnyxKey): boolean { + const entry = this.store.get(key); + return entry?.entryType === 'set'; + } + + /** + * Check whether the key has any pending entry (SET or MERGE). + */ + hasAny(key: OnyxKey): boolean { + return this.store.has(key); + } + + /** + * Returns the number of pending entries (both SET and MERGE). + */ + get size(): number { + return this.store.size; + } + + /** + * Clear all pending entries and cancel any scheduled flush. + */ + clear(): void { + this.store.clear(); + this.cancelScheduledFlush(); + } + + /** + * Immediately flush all pending entries to the storage provider. + * + * SET entries use reference identity: they stay in the map during flush and + * are only removed afterward if their reference hasn't changed (handling + * concurrent set-during-flush correctly). + * + * MERGE entries are removed from the map at flush start. New merges during + * flush create fresh entries, avoiding double-application of patches. + */ + async flushNow(): Promise { + if (this.isFlushing) { + // Wait for the current flush to finish, then flush again + return new Promise((resolve) => { + const waitForFlush = () => { + if (!this.isFlushing) { + resolve(this.flushNow()); + return; + } + setTimeout(waitForFlush, 5); + }; + waitForFlush(); + }); + } + + this.cancelScheduledFlush(); + + if (this.store.size === 0) { + return; + } + + this.isFlushing = true; + try { + // Separate entries by type + const setPairs: StorageKeyValuePair[] = []; + const setSnapshot: Map = new Map(); + const mergePairs: StorageKeyValuePair[] = []; + const mergeKeys: OnyxKey[] = []; + + for (const [key, entry] of this.store.entries()) { + if (entry.entryType === 'set') { + setPairs.push([entry.key, entry.value]); + setSnapshot.set(key, entry); + } else { + mergePairs.push([entry.key, entry.value, entry.replaceNullPatches]); + mergeKeys.push(key); + } + } + + // Remove MERGE entries from the map at flush start. + // New merges during flush will create fresh entries. + for (const key of mergeKeys) { + this.store.delete(key); + } + + // Flush both types concurrently + const promises: Array> = []; + if (setPairs.length > 0) { + promises.push(this.handlers.multiSet(setPairs)); + } + if (mergePairs.length > 0) { + promises.push(this.handlers.multiMerge(mergePairs)); + } + + await Promise.all(promises); + + // For SET entries: only remove if the reference hasn't changed + // (i.e., no set or merge was applied to this key during flush) + for (const [key, flushedEntry] of setSnapshot) { + if (this.store.get(key) === flushedEntry) { + this.store.delete(key); + } + } + } finally { + this.isFlushing = false; + } + + // If new entries were added during flush, schedule another one + if (this.store.size > 0) { + this.scheduleFlush(); + } + } + + /** + * Schedule a flush using the platform-specific scheduler. + * If a flush is already scheduled, this is a no-op. + */ + private scheduleFlush(): void { + if (this.flushHandle !== null) { + return; + } + + this.flushHandle = this.scheduleFlushFn(() => { + this.flushHandle = null; + void this.flushNow(); + }); + } + + /** + * Cancel any pending scheduled flush. + */ + private cancelScheduledFlush(): void { + if (this.flushHandle === null) { + return; + } + + this.cancelFlushFn(this.flushHandle); + this.flushHandle = null; + } +} + +export default WriteBuffer; +export type {FlushHandlers, BufferEntry, EntryType, FlushScheduler, CancelFlush, WriteBufferConfig}; diff --git a/lib/storage/index.ts b/lib/storage/index.ts index 07e7f7536..be04376cf 100644 --- a/lib/storage/index.ts +++ b/lib/storage/index.ts @@ -6,9 +6,10 @@ import MemoryOnlyProvider from './providers/MemoryOnlyProvider'; import type StorageProvider from './providers/types'; import * as GlobalSettings from '../GlobalSettings'; import decorateWithMetrics from '../metrics'; +import WriteBuffer from './WriteBuffer'; +import createBufferStore from './BufferStore'; let provider = PlatformStorage as StorageProvider; -let shouldKeepInstancesSync = false; let finishInitalization: (value?: unknown) => void; const initPromise = new Promise((resolve) => { finishInitalization = resolve; @@ -57,6 +58,24 @@ function tryOrDegradePerformance(fn: () => Promise | T, waitForInitializat }); } +/** + * The WriteBuffer is a patch-staging layer between Onyx's cache and the storage + * provider. It tracks two types of pending entries: + * - SET entries (full values) flushed via provider.multiSet() + * - MERGE entries (accumulated patches) flushed via provider.multiMerge(), + * preserving JSON_PATCH efficiency on SQLite + * + * All writes (set, merge) return immediately after staging in the WriteBuffer. + * Persistence happens asynchronously in coalesced batches. + */ +const writeBuffer = new WriteBuffer({ + handlers: { + multiSet: (pairs) => provider.multiSet(pairs), + multiMerge: (pairs) => provider.multiMerge(pairs), + }, + store: createBufferStore(), +}); + const storage: Storage = { /** * Returns the storage provider currently in use @@ -67,118 +86,158 @@ const storage: Storage = { /** * Initializes all providers in the list of storage providers - * and enables fallback providers if necessary + * and enables fallback providers if necessary. + * + * If the provider's init() returns a Promise (e.g. WorkerStorageProvider + * waiting for the web worker to finish setting up its backend), we await + * it so that finishInitalization() only fires after the provider is truly + * ready for data operations. */ init() { - tryOrDegradePerformance(provider.init, false).finally(() => { + tryOrDegradePerformance(() => { + const result = provider.init(); + // provider.init() may return void or Promise + return result instanceof Promise ? result : Promise.resolve(); + }, false).finally(() => { finishInitalization(); }); }, /** - * Get the value of a given key or return `null` if it's not available + * Get the value of a given key or return `null` if it's not available. + * + * - If the key has a pending SET entry, it is returned directly from memory. + * - If the key has a pending MERGE entry (a patch delta, not a full value), + * the write buffer is flushed first so the provider has the correct merged + * value on disk, then the read proceeds normally. + * - Otherwise, the read goes straight to the provider. */ - getItem: (key) => tryOrDegradePerformance(() => provider.getItem(key)), + getItem: (key) => + tryOrDegradePerformance(() => { + if (writeBuffer.has(key)) { + return Promise.resolve(writeBuffer.get(key)); + } + if (writeBuffer.hasAny(key)) { + return writeBuffer.flushNow().then(() => provider.getItem(key)); + } + return provider.getItem(key); + }), /** - * Get multiple key-value pairs for the give array of keys in a batch + * Get multiple key-value pairs for the give array of keys in a batch. + * + * Keys with pending SET entries are served from memory. If any remaining + * keys have pending MERGE entries, the write buffer is flushed before + * reading from the provider so the on-disk values are up to date. */ - multiGet: (keys) => tryOrDegradePerformance(() => provider.multiGet(keys)), + multiGet: (keys) => + tryOrDegradePerformance(() => { + const bufferedKeys: string[] = []; + const cleanKeys: string[] = []; + let hasPendingMerges = false; + + for (const key of keys) { + if (writeBuffer.has(key)) { + bufferedKeys.push(key); + } else { + cleanKeys.push(key); + if (writeBuffer.hasAny(key)) { + hasPendingMerges = true; + } + } + } + + // If all keys have SET entries, skip the provider call entirely + if (cleanKeys.length === 0) { + return Promise.resolve(bufferedKeys.map((key) => [key, writeBuffer.get(key)])); + } + + // If any clean keys have pending MERGE entries, flush first + const readyPromise = hasPendingMerges ? writeBuffer.flushNow() : Promise.resolve(); + + return readyPromise.then(() => + provider.multiGet(cleanKeys).then((providerResults) => { + const bufferedResults = bufferedKeys.map((key) => [key, writeBuffer.get(key)] as [string, unknown]); + return [...providerResults, ...bufferedResults]; + }), + ); + }), /** - * Sets the value for a given key. The only requirement is that the value should be serializable to JSON string + * Sets the value for a given key. The value is staged in the write buffer + * as a SET entry and flushed to storage asynchronously in a coalesced batch. + * + * Cross-tab broadcasting is handled by the unified worker after persistence, + * so no InstanceSync send calls are needed here. */ setItem: (key, value) => tryOrDegradePerformance(() => { - const promise = provider.setItem(key, value); - - if (shouldKeepInstancesSync) { - return promise.then(() => InstanceSync.setItem(key)); - } - - return promise; + writeBuffer.set(key, value); + return Promise.resolve(); }), /** - * Stores multiple key-value pairs in a batch + * Stores multiple key-value pairs. All values are staged in the write buffer + * as SET entries and flushed to storage asynchronously in a coalesced batch. */ multiSet: (pairs) => tryOrDegradePerformance(() => { - const promise = provider.multiSet(pairs); - - if (shouldKeepInstancesSync) { - return promise.then(() => InstanceSync.multiSet(pairs.map((pair) => pair[0]))); - } - - return promise; + writeBuffer.setMany(pairs); + return Promise.resolve(); }), /** - * Merging an existing value with a new one + * Merging an existing value with a new one. + * The patch is staged in the write buffer as a MERGE entry. If the key + * already has a pending SET, the patch is applied to the full value + * in-memory. If it already has a pending MERGE, patches are accumulated. + * Returns immediately -- no flushNow() needed. */ mergeItem: (key, change, replaceNullPatches) => tryOrDegradePerformance(() => { - const promise = provider.mergeItem(key, change, replaceNullPatches); - - if (shouldKeepInstancesSync) { - return promise.then(() => InstanceSync.mergeItem(key)); - } - - return promise; + writeBuffer.merge(key, change, replaceNullPatches); + return Promise.resolve(); }), /** - * Multiple merging of existing and new values in a batch - * This function also removes all nested null values from an object. + * Multiple merging of existing and new values in a batch. + * Each pair's patch is staged in the write buffer as a MERGE entry. + * Returns immediately -- no flushNow() needed. */ multiMerge: (pairs) => tryOrDegradePerformance(() => { - const promise = provider.multiMerge(pairs); - - if (shouldKeepInstancesSync) { - return promise.then(() => InstanceSync.multiMerge(pairs.map((pair) => pair[0]))); + for (const [key, value, replaceNullPatches] of pairs) { + writeBuffer.merge(key, value, replaceNullPatches); } - - return promise; + return Promise.resolve(); }), /** - * Removes given key and its value + * Removes given key and its value. + * Also removes the key from the write buffer if it has a pending write. */ removeItem: (key) => tryOrDegradePerformance(() => { - const promise = provider.removeItem(key); - - if (shouldKeepInstancesSync) { - return promise.then(() => InstanceSync.removeItem(key)); - } - - return promise; + writeBuffer.remove(key); + return provider.removeItem(key); }), /** - * Remove given keys and their values + * Remove given keys and their values. + * Also removes the keys from the write buffer if they have pending writes. */ removeItems: (keys) => tryOrDegradePerformance(() => { - const promise = provider.removeItems(keys); - - if (shouldKeepInstancesSync) { - return promise.then(() => InstanceSync.removeItems(keys)); - } - - return promise; + writeBuffer.removeMany(keys); + return provider.removeItems(keys); }), /** - * Clears everything + * Clears everything. Clears the write buffer first, then the provider. */ clear: () => tryOrDegradePerformance(() => { - if (shouldKeepInstancesSync) { - return InstanceSync.clear(() => provider.clear()); - } - + writeBuffer.clear(); return provider.clear(); }), @@ -193,13 +252,17 @@ const storage: Storage = { getDatabaseSize: () => tryOrDegradePerformance(() => provider.getDatabaseSize()), /** - * @param onStorageKeyChanged - Storage synchronization mechanism keeping all opened tabs in sync (web only) + * Initializes the cross-tab sync receiver. On web, InstanceSync listens on + * BroadcastChannel for value-bearing messages from other tabs' workers and + * calls onStorageKeyChanged to update the cache. No send-side logic is + * needed here -- the unified worker handles broadcasting after persistence. + * + * @param onStorageKeyChanged - Callback invoked when another tab changes a key */ keepInstancesSync(onStorageKeyChanged) { // If InstanceSync shouldn't be used, it means we're on a native platform and we don't need to keep instances in sync if (!InstanceSync.shouldBeUsed) return; - shouldKeepInstancesSync = true; InstanceSync.init(onStorageKeyChanged, this); }, }; diff --git a/lib/storage/platforms/index.native.ts b/lib/storage/platforms/index.native.ts index 95822c4a5..7b15ab776 100644 --- a/lib/storage/platforms/index.native.ts +++ b/lib/storage/platforms/index.native.ts @@ -1,3 +1,56 @@ -import NativeStorage from '../providers/SQLiteProvider'; +/** + * Native (iOS/Android) storage platform selection. + * + * Uses the native SQLite provider (react-native-nitro-sqlite) with persistence + * managed by the NativeFlushWorker. The WriteBuffer populates a HybridObject- + * backed BufferStore (shared memory), and the NativeFlushWorker periodically + * drains it and persists to SQLite. + * + * Read operations go directly to the SQLite provider (bypassing the buffer). + * The WriteBuffer's read-through handles in-flight writes. + * + * NOTE: The NativeFlushWorker currently uses setInterval as a transitional + * implementation. Once react-native-worklets integration is complete, the + * flush logic will run on a true Worklet Worker Runtime background thread. + */ +import createNativeFlushWorker from '../NativeFlushWorker'; +import createNativeBufferStore from '../BufferStore/index.native'; +import type StorageProvider from '../providers/types'; + +// Create the shared buffer (HybridObject or JS Map fallback) +const bufferStore = createNativeBufferStore(); + +// Create and start the flush worker +const flushWorker = createNativeFlushWorker(bufferStore); +flushWorker.start(); + +// The native provider is accessed via the flush worker for read operations +const nativeProvider = flushWorker.getProvider(); + +/** + * Native storage provider that delegates reads to the SQLite provider + * and uses the WriteBuffer + NativeFlushWorker for writes. + */ +const NativeStorage: StorageProvider = { + store: nativeProvider.store, + name: nativeProvider.name, + + init() { + // Already initialized by flushWorker.start() + }, + + getItem: (key) => nativeProvider.getItem(key), + multiGet: (keys) => nativeProvider.multiGet(keys), + setItem: (key, value) => nativeProvider.setItem(key, value), + multiSet: (pairs) => nativeProvider.multiSet(pairs), + multiMerge: (pairs) => nativeProvider.multiMerge(pairs), + mergeItem: (key, change, replaceNullPatches) => nativeProvider.mergeItem(key, change, replaceNullPatches), + getAllKeys: () => nativeProvider.getAllKeys(), + removeItem: (key) => nativeProvider.removeItem(key), + removeItems: (keys) => nativeProvider.removeItems(keys), + clear: () => nativeProvider.clear(), + getDatabaseSize: () => nativeProvider.getDatabaseSize(), +}; export default NativeStorage; +export {bufferStore, flushWorker}; diff --git a/lib/storage/platforms/index.ts b/lib/storage/platforms/index.ts index 0b95dc97d..167f05c2f 100644 --- a/lib/storage/platforms/index.ts +++ b/lib/storage/platforms/index.ts @@ -1,3 +1,42 @@ -import WebStorage from '../providers/IDBKeyValProvider'; +/** + * Web storage platform selection. + * + * Uses the WorkerStorageProvider to run all persistence off the main thread. + * Detects OPFS support to choose the best backend: + * - OPFS + Worker available: SQLite via @sqlite.org/sqlite-wasm with opfs-sahpool VFS + * - No OPFS: IDBKeyValProvider fallback (still runs in a worker) + */ +import createWorkerStorageProvider from '../WorkerStorageProvider'; + +/** + * Check if Web Workers are supported in the current environment. + */ +function isWorkerSupported(): boolean { + return typeof Worker !== 'undefined'; +} + +/** + * Check if the Origin Private File System (OPFS) is available. + * OPFS is required for SQLite persistence via the opfs-sahpool VFS. + * This is a synchronous heuristic -- actual OPFS availability is confirmed + * by the SQLite WASM library at init time. + */ +function isOPFSSupported(): boolean { + return typeof navigator !== 'undefined' && typeof navigator.storage !== 'undefined' && typeof navigator.storage.getDirectory === 'function'; +} + +/** + * Select the best backend based on browser capabilities. + * Falls back to IDB if OPFS is not available. + */ +function selectBackend(): 'sqlite' | 'idb' { + if (isWorkerSupported() && isOPFSSupported()) { + return 'sqlite'; + } + return 'idb'; +} + +const backend = selectBackend(); +const WebStorage = createWorkerStorageProvider(backend); export default WebStorage; diff --git a/lib/storage/providers/SQLiteProvider.ts b/lib/storage/providers/SQLiteProvider/index.native.ts similarity index 55% rename from lib/storage/providers/SQLiteProvider.ts rename to lib/storage/providers/SQLiteProvider/index.native.ts index 1d2927d8c..0a2a25aed 100644 --- a/lib/storage/providers/SQLiteProvider.ts +++ b/lib/storage/providers/SQLiteProvider/index.native.ts @@ -1,14 +1,22 @@ /** - * The SQLiteStorage provider stores everything in a key/value store by - * converting the value to a JSON string + * Native SQLite Storage Provider + * + * Implements the StorageProvider interface using react-native-nitro-sqlite. + * This module is called from the Worklet Worker Runtime (background JS thread) + * managed by NativeFlushWorker, NOT from the main thread. + * + * Uses synchronous APIs (execute, executeBatch) since the Worklet Worker Runtime + * runs on a dedicated background thread where blocking is acceptable and avoids + * unnecessary Promise overhead. */ import type {BatchQueryCommand, NitroSQLiteConnection} from 'react-native-nitro-sqlite'; import {enableSimpleNullHandling, open} from 'react-native-nitro-sqlite'; import {getFreeDiskStorage} from 'react-native-device-info'; -import type {FastMergeReplaceNullPatch} from '../../utils'; -import utils from '../../utils'; -import type StorageProvider from './types'; -import type {StorageKeyList, StorageKeyValuePair} from './types'; +import type {FastMergeReplaceNullPatch} from '../../../utils'; +import utils from '../../../utils'; +import type StorageProvider from '../types'; +import type {StorageKeyList, StorageKeyValuePair} from '../types'; +import * as Queries from '../SQLiteQueries'; // By default, NitroSQLite does not accept nullish values due to current limitations in Nitro Modules. // This flag enables a feature in NitroSQLite that allows for nullish values to be passed to operations, such as "execute" or "executeBatch". @@ -76,63 +84,59 @@ const provider: StorageProvider = { init() { provider.store = open({name: DB_NAME}); - provider.store.execute('CREATE TABLE IF NOT EXISTS keyvaluepairs (record_key TEXT NOT NULL PRIMARY KEY , valueJSON JSON NOT NULL) WITHOUT ROWID;'); + provider.store.execute(Queries.CREATE_TABLE); // All of the 3 pragmas below were suggested by SQLite team. // You can find more info about them here: https://www.sqlite.org/pragma.html - provider.store.execute('PRAGMA CACHE_SIZE=-20000;'); - provider.store.execute('PRAGMA synchronous=NORMAL;'); - provider.store.execute('PRAGMA journal_mode=WAL;'); + provider.store.execute(Queries.PRAGMA_CACHE_SIZE); + provider.store.execute(Queries.PRAGMA_SYNCHRONOUS); + provider.store.execute(Queries.PRAGMA_JOURNAL_MODE); }, getItem(key) { if (!provider.store) { throw new Error('Store is not initialized!'); } - return provider.store.executeAsync('SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key = ?;', [key]).then(({rows}) => { - if (!rows || rows?.length === 0) { - return null; - } - const result = rows?.item(0); - - if (result == null) { - return null; - } - - return JSON.parse(result.valueJSON); - }); + const {rows} = provider.store.execute(Queries.GET_ITEM, [key]); + if (!rows || rows.length === 0) { + return Promise.resolve(null); + } + const result = rows.item(0); + if (result == null) { + return Promise.resolve(null); + } + return Promise.resolve(JSON.parse(result.valueJSON)); }, multiGet(keys) { if (!provider.store) { throw new Error('Store is not initialized!'); } - const placeholders = keys.map(() => '?').join(','); - const command = `SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key IN (${placeholders});`; - return provider.store.executeAsync(command, keys).then(({rows}) => { - // eslint-disable-next-line no-underscore-dangle - const result = rows?._array.map((row) => [row.record_key, JSON.parse(row.valueJSON)]); - return (result ?? []) as StorageKeyValuePair[]; - }); + const command = Queries.buildMultiGetQuery(keys.length); + const {rows} = provider.store.execute(command, keys); + // eslint-disable-next-line no-underscore-dangle + const result = rows?._array.map((row) => [row.record_key, JSON.parse(row.valueJSON)]); + return Promise.resolve((result ?? []) as StorageKeyValuePair[]); }, setItem(key, value) { if (!provider.store) { throw new Error('Store is not initialized!'); } - return provider.store.executeAsync('REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, ?);', [key, JSON.stringify(value)]).then(() => undefined); + provider.store.execute(Queries.SET_ITEM, [key, JSON.stringify(value)]); + return Promise.resolve(); }, multiSet(pairs) { if (!provider.store) { throw new Error('Store is not initialized!'); } - const query = 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));'; const params = pairs.map((pair) => [pair[0], JSON.stringify(pair[1] === undefined ? null : pair[1])]); if (utils.isEmptyObject(params)) { return Promise.resolve(); } - return provider.store.executeBatchAsync([{query, params}]).then(() => undefined); + provider.store.executeBatch([{query: Queries.MULTI_SET_ITEM, params}]); + return Promise.resolve(); }, multiMerge(pairs) { if (!provider.store) { @@ -141,19 +145,7 @@ const provider: StorageProvider = { const commands: BatchQueryCommand[] = []; - // Query to merge the change into the DB value. - const patchQuery = `INSERT INTO keyvaluepairs (record_key, valueJSON) - VALUES (:key, JSON(:value)) - ON CONFLICT DO UPDATE - SET valueJSON = JSON_PATCH(valueJSON, JSON(:value)); - `; const patchQueryArguments: string[][] = []; - - // Query to fully replace the nested objects of the DB value. - const replaceQuery = `UPDATE keyvaluepairs - SET valueJSON = JSON_REPLACE(valueJSON, ?, JSON(?)) - WHERE record_key = ?; - `; const replaceQueryArguments: string[][] = []; const nonNullishPairs = pairs.filter((pair) => pair[1] !== undefined); @@ -172,12 +164,13 @@ const provider: StorageProvider = { } } - commands.push({query: patchQuery, params: patchQueryArguments}); + commands.push({query: Queries.MERGE_ITEM_PATCH, params: patchQueryArguments}); if (replaceQueryArguments.length > 0) { - commands.push({query: replaceQuery, params: replaceQueryArguments}); + commands.push({query: Queries.MERGE_ITEM_REPLACE, params: replaceQueryArguments}); } - return provider.store.executeBatchAsync(commands).then(() => undefined); + provider.store.executeBatch(commands); + return Promise.resolve(); }, mergeItem(key, change, replaceNullPatches) { // Since Onyx already merged the existing value with the changes, we can just set the value directly. @@ -188,50 +181,50 @@ const provider: StorageProvider = { throw new Error('Store is not initialized!'); } - return provider.store.executeAsync('SELECT record_key FROM keyvaluepairs;').then(({rows}) => { - // eslint-disable-next-line no-underscore-dangle - const result = rows?._array.map((row) => row.record_key); - return (result ?? []) as StorageKeyList; - }); + const {rows} = provider.store.execute(Queries.GET_ALL_KEYS); + // eslint-disable-next-line no-underscore-dangle + const result = rows?._array.map((row: {record_key: string}) => row.record_key); + return Promise.resolve((result ?? []) as StorageKeyList); }, removeItem(key) { if (!provider.store) { throw new Error('Store is not initialized!'); } - return provider.store.executeAsync('DELETE FROM keyvaluepairs WHERE record_key = ?;', [key]).then(() => undefined); + provider.store.execute(Queries.REMOVE_ITEM, [key]); + return Promise.resolve(); }, removeItems(keys) { if (!provider.store) { throw new Error('Store is not initialized!'); } - const placeholders = keys.map(() => '?').join(','); - const query = `DELETE FROM keyvaluepairs WHERE record_key IN (${placeholders});`; - return provider.store.executeAsync(query, keys).then(() => undefined); + const query = Queries.buildRemoveItemsQuery(keys.length); + provider.store.execute(query, keys); + return Promise.resolve(); }, clear() { if (!provider.store) { throw new Error('Store is not initialized!'); } - return provider.store.executeAsync('DELETE FROM keyvaluepairs;', []).then(() => undefined); + provider.store.execute(Queries.CLEAR, []); + return Promise.resolve(); }, getDatabaseSize() { if (!provider.store) { throw new Error('Store is not initialized!'); } - return Promise.all([provider.store.executeAsync('PRAGMA page_size;'), provider.store.executeAsync('PRAGMA page_count;'), getFreeDiskStorage()]).then( - ([pageSizeResult, pageCountResult, bytesRemaining]) => { - const pageSize = pageSizeResult.rows?.item(0)?.page_size ?? 0; - const pageCount = pageCountResult.rows?.item(0)?.page_count ?? 0; - return { - bytesUsed: pageSize * pageCount, - bytesRemaining, - }; - }, - ); + const pageSizeResult = provider.store.execute(Queries.PRAGMA_PAGE_SIZE); + const pageCountResult = provider.store.execute(Queries.PRAGMA_PAGE_COUNT); + const pageSize = pageSizeResult.rows?.item(0)?.page_size ?? 0; + const pageCount = pageCountResult.rows?.item(0)?.page_count ?? 0; + + return getFreeDiskStorage().then((bytesRemaining) => ({ + bytesUsed: pageSize * pageCount, + bytesRemaining, + })); }, }; diff --git a/lib/storage/providers/SQLiteProvider/index.web.ts b/lib/storage/providers/SQLiteProvider/index.web.ts new file mode 100644 index 000000000..dc57c0f21 --- /dev/null +++ b/lib/storage/providers/SQLiteProvider/index.web.ts @@ -0,0 +1,261 @@ +/** + * Web SQLite Storage Provider + * + * Implements the StorageProvider interface using @sqlite.org/sqlite-wasm with + * the opfs-sahpool VFS for OPFS-backed persistence. This module is imported + * by the unified storage worker (lib/storage/worker.ts), NOT by the main thread. + * + * All methods are synchronous (SQLite WASM operations are sync), but conform + * to the StorageProvider interface which returns Promises. + */ + +import utils from '../../../utils'; +import type StorageProvider from '../types'; +import type {StorageKeyList, StorageKeyValuePair} from '../types'; +import * as Queries from '../SQLiteQueries'; + +// Type declarations for the SQLite WASM API +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type SQLiteDB = any; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type SQLiteStmt = any; + +// --------------------------------------------------------------------------- +// SQLite WASM and database state +// --------------------------------------------------------------------------- + +let db: SQLiteDB | null = null; + +// Prepared statements (initialized once, reused for all operations) +let stmtGetItem: SQLiteStmt | null = null; +let stmtSetItem: SQLiteStmt | null = null; +let stmtSetItemJson: SQLiteStmt | null = null; +let stmtMergePatch: SQLiteStmt | null = null; +let stmtMergeReplace: SQLiteStmt | null = null; +let stmtRemoveItem: SQLiteStmt | null = null; +let stmtGetAllKeys: SQLiteStmt | null = null; +let stmtClear: SQLiteStmt | null = null; + +/** + * Marker key used by fastMerge to flag object replacements. + * Duplicated here from utils to avoid importing the full utils module into the worker. + */ +const ONYX_INTERNALS__REPLACE_OBJECT_MARK = 'ONYX_INTERNALS__REPLACE_OBJECT_MARK'; + +/** + * JSON.stringify replacer that strips internal object-replacement markers + * before persisting merge patches. + */ +function objectMarkRemover(key: string, value: unknown) { + if (key === ONYX_INTERNALS__REPLACE_OBJECT_MARK) return undefined; + return value; +} + +/** + * Transforms replaceNullPatches into [jsonPath, valueJSON, key] tuples for + * the JSON_REPLACE prepared statement. + */ +function generateJSONReplaceSQLQueries(key: string, patches: [string[], unknown][]): string[][] { + return patches.map(([pathArray, value]) => { + const jsonPath = `$.${pathArray.join('.')}`; + return [jsonPath, JSON.stringify(value), key]; + }); +} + +const provider: StorageProvider = { + store: null, + + /** + * The name of the provider that can be printed to the logs + */ + name: 'SQLiteProvider (Web)', + + /** + * Initialize the SQLite WASM database with opfs-sahpool VFS. + */ + init() { + // Actual async initialization happens via initAsync() below. + // The worker calls initAsync() and awaits it. + }, + + getItem(key) { + stmtGetItem.bind([key]); + if (stmtGetItem.step()) { + const valueJSON = stmtGetItem.getString(1) as string; + stmtGetItem.reset(); + return Promise.resolve(JSON.parse(valueJSON)); + } + stmtGetItem.reset(); + return Promise.resolve(null); + }, + + multiGet(keys) { + const results: StorageKeyValuePair[] = []; + for (const key of keys) { + stmtGetItem.bind([key]); + if (stmtGetItem.step()) { + results.push([stmtGetItem.getString(0) as string, JSON.parse(stmtGetItem.getString(1) as string)]); + } + stmtGetItem.reset(); + } + return Promise.resolve(results); + }, + + setItem(key, value) { + const valueJSON = JSON.stringify(value); + stmtSetItem.bind([key, valueJSON]); + stmtSetItem.stepReset(); + return Promise.resolve(); + }, + + multiSet(pairs) { + if (utils.isEmptyObject(pairs)) { + return Promise.resolve(); + } + db.exec('BEGIN;'); + try { + for (const [key, value] of pairs) { + const valueJSON = JSON.stringify(value === undefined ? null : value); + stmtSetItemJson.bind([key, valueJSON]); + stmtSetItemJson.stepReset(); + } + db.exec('COMMIT;'); + } catch (e) { + db.exec('ROLLBACK;'); + throw e; + } + return Promise.resolve(); + }, + + multiMerge(pairs) { + const nonNullishPairs = pairs.filter((pair) => pair[1] !== undefined); + db.exec('BEGIN;'); + try { + for (const [key, change, replaceNullPatches] of nonNullishPairs) { + // Stringify the change, stripping internal object-replacement markers + const changeJSON = JSON.stringify(change, objectMarkRemover); + + // Apply JSON_PATCH merge (named params match SQLiteQueries.MERGE_ITEM_PATCH) + stmtMergePatch.bind({':key': key, ':value': changeJSON}); + stmtMergePatch.stepReset(); + + // Generate and apply JSON_REPLACE patches if any + const patches = (replaceNullPatches ?? []) as [string[], unknown][]; + if (patches.length > 0) { + const replaceQueries = generateJSONReplaceSQLQueries(key, patches); + for (const [jsonPath, patchValue, replaceKey] of replaceQueries) { + stmtMergeReplace.bind([jsonPath, patchValue, replaceKey]); + stmtMergeReplace.stepReset(); + } + } + } + db.exec('COMMIT;'); + } catch (e) { + db.exec('ROLLBACK;'); + throw e; + } + return Promise.resolve(); + }, + + mergeItem(key, change, replaceNullPatches) { + return provider.multiMerge([[key, change, replaceNullPatches]]); + }, + + getAllKeys() { + const keys: StorageKeyList = []; + while (stmtGetAllKeys.step()) { + keys.push(stmtGetAllKeys.getString(0) as string); + } + stmtGetAllKeys.reset(); + return Promise.resolve(keys); + }, + + removeItem(key) { + stmtRemoveItem.bind([key]); + stmtRemoveItem.stepReset(); + return Promise.resolve(); + }, + + removeItems(keys) { + db.exec('BEGIN;'); + try { + for (const key of keys) { + stmtRemoveItem.bind([key]); + stmtRemoveItem.stepReset(); + } + db.exec('COMMIT;'); + } catch (e) { + db.exec('ROLLBACK;'); + throw e; + } + return Promise.resolve(); + }, + + clear() { + stmtClear.stepReset(); + return Promise.resolve(); + }, + + getDatabaseSize() { + const pageSizeRow = db.exec('PRAGMA page_size;', {returnValue: 'resultRows'}); + const pageCountRow = db.exec('PRAGMA page_count;', {returnValue: 'resultRows'}); + + const pageSize = pageSizeRow?.[0]?.[0] ?? 0; + const pageCount = pageCountRow?.[0]?.[0] ?? 0; + + return Promise.resolve({ + bytesUsed: (pageSize as number) * (pageCount as number), + bytesRemaining: Number.POSITIVE_INFINITY, + }); + }, +}; + +/** + * Async initialization for the SQLite WASM database. + * Must be called (and awaited) before using any other provider methods. + */ +async function initAsync(): Promise { + // Dynamic import of the SQLite WASM module + // eslint-disable-next-line @typescript-eslint/no-var-requires + const sqlite3InitModule = (await import('@sqlite.org/sqlite-wasm')).default; + const sqlite3 = await sqlite3InitModule(); + + // Try to install opfs-sahpool VFS + try { + const poolUtil = await sqlite3.installOpfsSAHPoolVfs({ + name: 'opfs-sahpool', + directory: '/onyx-opfs', + initialCapacity: 6, + }); + + // Open the database using the opfs-sahpool VFS + db = new poolUtil.OpfsSAHPoolDb('/OnyxDB'); + } catch (opfsError) { + // If opfs-sahpool is not available, fall back to in-memory + // (the main thread will handle the full IDB fallback) + console.warn('opfs-sahpool VFS not available, using in-memory SQLite:', opfsError); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + db = new sqlite3.oo1.DB(':memory:'); + } + + // Initialize the schema and pragmas + db.exec(Queries.CREATE_TABLE); + db.exec(Queries.PRAGMA_CACHE_SIZE); + db.exec(Queries.PRAGMA_SYNCHRONOUS); + db.exec(Queries.PRAGMA_JOURNAL_MODE); + + // Prepare reusable statements using shared SQL query constants + stmtGetItem = db.prepare(Queries.GET_ITEM); + stmtSetItem = db.prepare(Queries.SET_ITEM); + stmtSetItemJson = db.prepare(Queries.MULTI_SET_ITEM); + stmtMergePatch = db.prepare(Queries.MERGE_ITEM_PATCH); + stmtMergeReplace = db.prepare(Queries.MERGE_ITEM_REPLACE); + stmtRemoveItem = db.prepare(Queries.REMOVE_ITEM); + stmtGetAllKeys = db.prepare(Queries.GET_ALL_KEYS); + stmtClear = db.prepare(Queries.CLEAR); + + provider.store = db; +} + +export default provider; +export {initAsync}; diff --git a/lib/storage/providers/SQLiteQueries.ts b/lib/storage/providers/SQLiteQueries.ts new file mode 100644 index 000000000..d0096e948 --- /dev/null +++ b/lib/storage/providers/SQLiteQueries.ts @@ -0,0 +1,104 @@ +/** + * Shared SQL query constants used by both native and web SQLite providers. + * + * These strings are consumed by react-native-nitro-sqlite on iOS/Android and + * by @sqlite.org/sqlite-wasm on web so they must be plain SQL with `?` or + * named-parameter placeholders. + */ + +// --------------------------------------------------------------------------- +// Initialization +// --------------------------------------------------------------------------- + +const CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS keyvaluepairs (record_key TEXT NOT NULL PRIMARY KEY, valueJSON JSON NOT NULL) WITHOUT ROWID;'; +const PRAGMA_CACHE_SIZE = 'PRAGMA CACHE_SIZE=-20000;'; +const PRAGMA_SYNCHRONOUS = 'PRAGMA synchronous=NORMAL;'; +const PRAGMA_JOURNAL_MODE = 'PRAGMA journal_mode=WAL;'; + +// --------------------------------------------------------------------------- +// Read operations +// --------------------------------------------------------------------------- + +const GET_ITEM = 'SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key = ?;'; + +/** + * Builds a SELECT ... WHERE record_key IN (...) query for a given number of keys. + */ +function buildMultiGetQuery(count: number): string { + const placeholders = new Array(count).fill('?').join(','); + return `SELECT record_key, valueJSON FROM keyvaluepairs WHERE record_key IN (${placeholders});`; +} + +const GET_ALL_KEYS = 'SELECT record_key FROM keyvaluepairs;'; + +// --------------------------------------------------------------------------- +// Write operations +// --------------------------------------------------------------------------- + +const SET_ITEM = 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, ?);'; +const MULTI_SET_ITEM = 'REPLACE INTO keyvaluepairs (record_key, valueJSON) VALUES (?, json(?));'; + +// --------------------------------------------------------------------------- +// Merge operations +// --------------------------------------------------------------------------- + +/** + * INSERT-or-PATCH: inserts if the key doesn't exist, otherwise applies + * JSON_PATCH to merge the new value into the existing one. + */ +const MERGE_ITEM_PATCH = `INSERT INTO keyvaluepairs (record_key, valueJSON) + VALUES (:key, JSON(:value)) + ON CONFLICT DO UPDATE + SET valueJSON = JSON_PATCH(valueJSON, JSON(:value)); +`; + +/** + * Replaces a specific JSON path inside an existing value. + * Used to apply FastMergeReplaceNullPatch entries after the JSON_PATCH merge. + */ +const MERGE_ITEM_REPLACE = `UPDATE keyvaluepairs + SET valueJSON = JSON_REPLACE(valueJSON, ?, JSON(?)) + WHERE record_key = ?; +`; + +// --------------------------------------------------------------------------- +// Delete operations +// --------------------------------------------------------------------------- + +const REMOVE_ITEM = 'DELETE FROM keyvaluepairs WHERE record_key = ?;'; + +/** + * Builds a DELETE ... WHERE record_key IN (...) query for a given number of keys. + */ +function buildRemoveItemsQuery(count: number): string { + const placeholders = new Array(count).fill('?').join(','); + return `DELETE FROM keyvaluepairs WHERE record_key IN (${placeholders});`; +} + +const CLEAR = 'DELETE FROM keyvaluepairs;'; + +// --------------------------------------------------------------------------- +// Size / diagnostics +// --------------------------------------------------------------------------- + +const PRAGMA_PAGE_SIZE = 'PRAGMA page_size;'; +const PRAGMA_PAGE_COUNT = 'PRAGMA page_count;'; + +export { + CREATE_TABLE, + PRAGMA_CACHE_SIZE, + PRAGMA_SYNCHRONOUS, + PRAGMA_JOURNAL_MODE, + GET_ITEM, + buildMultiGetQuery, + GET_ALL_KEYS, + SET_ITEM, + MULTI_SET_ITEM, + MERGE_ITEM_PATCH, + MERGE_ITEM_REPLACE, + REMOVE_ITEM, + buildRemoveItemsQuery, + CLEAR, + PRAGMA_PAGE_SIZE, + PRAGMA_PAGE_COUNT, +}; diff --git a/lib/storage/providers/types.ts b/lib/storage/providers/types.ts index ab275e39c..a70346086 100644 --- a/lib/storage/providers/types.ts +++ b/lib/storage/providers/types.ts @@ -20,9 +20,10 @@ type StorageProvider = { name: string; /** - * Initializes the storage provider + * Initializes the storage provider. + * May return a Promise if initialization is asynchronous (e.g. spawning a worker). */ - init: () => void; + init: () => void | Promise; /** * Gets the value of a given key or return `null` if it's not available in storage diff --git a/lib/storage/worker.ts b/lib/storage/worker.ts new file mode 100644 index 000000000..5675b1d3b --- /dev/null +++ b/lib/storage/worker.ts @@ -0,0 +1,265 @@ +/** + * Unified Storage Web Worker + * + * Provider-agnostic worker that handles all database operations off the main + * thread. On init, it receives a backend choice ('sqlite' or 'idb') and + * dynamically imports the appropriate StorageProvider implementation. + * + * Messages are processed **serially** via a queue to ensure that the init + * message completes before any data operations begin, and that concurrent + * messages never race against each other. + * + * After each write operation, changed keys are broadcast to other tabs via + * BroadcastChannel so they can update their caches. + */ + +import type StorageProvider from './providers/types'; + +// --------------------------------------------------------------------------- +// Message types for main-thread <-> worker communication +// --------------------------------------------------------------------------- + +type InitMessage = {type: 'init'; id: string; backend: 'sqlite' | 'idb'}; +type GetItemMessage = {type: 'getItem'; id: string; key: string}; +type MultiGetMessage = {type: 'multiGet'; id: string; keys: string[]}; +type SetItemMessage = {type: 'setItem'; id: string; key: string; value: unknown}; +type MultiSetMessage = {type: 'multiSet'; id: string; pairs: [string, unknown][]}; +type MultiMergeMessage = {type: 'multiMerge'; id: string; pairs: [string, unknown, unknown[] | undefined][]}; +type GetAllKeysMessage = {type: 'getAllKeys'; id: string}; +type RemoveItemMessage = {type: 'removeItem'; id: string; key: string}; +type RemoveItemsMessage = {type: 'removeItems'; id: string; keys: string[]}; +type ClearMessage = {type: 'clear'; id: string}; +type GetDatabaseSizeMessage = {type: 'getDatabaseSize'; id: string}; + +type WorkerMessage = + | InitMessage + | GetItemMessage + | MultiGetMessage + | SetItemMessage + | MultiSetMessage + | MultiMergeMessage + | GetAllKeysMessage + | RemoveItemMessage + | RemoveItemsMessage + | ClearMessage + | GetDatabaseSizeMessage; + +type ResultMessage = {type: 'result'; id: string; data?: unknown; error?: string}; + +// --------------------------------------------------------------------------- +// State +// --------------------------------------------------------------------------- + +let provider: StorageProvider | null = null; +let broadcastChannel: BroadcastChannel | null = null; + +const BROADCAST_CHANNEL_NAME = 'onyx-sync'; + +// --------------------------------------------------------------------------- +// Serial message processing queue +// +// Each incoming message is pushed into `messageQueue`. A single `processQueue` +// loop pops one message at a time, awaits its async handler, then moves to the +// next. This guarantees: +// 1. `init` completes before any data operation touches `provider` +// 2. No two messages run concurrently (avoiding IDB transaction races) +// --------------------------------------------------------------------------- + +const messageQueue: WorkerMessage[] = []; +let processing = false; + +async function processQueue(): Promise { + if (processing) { + return; // another processQueue loop is already active + } + processing = true; + + while (messageQueue.length > 0) { + const msg = messageQueue.shift()!; + try { + await handleMessage(msg); + } catch (error) { + sendResult(msg.id, undefined, error instanceof Error ? error.message : String(error)); + } + } + + processing = false; +} + +// --------------------------------------------------------------------------- +// Broadcasting (value-bearing messages for cross-tab sync) +// --------------------------------------------------------------------------- + +/** + * Broadcast SET operations with full values to other tabs. + * Receiving tabs can update their caches directly without re-reading from storage. + */ +function broadcastSet(pairs: [string, unknown][]): void { + if (broadcastChannel && pairs.length > 0) { + broadcastChannel.postMessage({type: 'set', pairs}); + } +} + +/** + * Broadcast MERGE operations with raw patches to other tabs. + * Receiving tabs apply fastMerge against their cached values. + */ +function broadcastMerge(pairs: [string, unknown][]): void { + if (broadcastChannel && pairs.length > 0) { + broadcastChannel.postMessage({type: 'merge', pairs}); + } +} + +/** + * Broadcast REMOVE operations to other tabs. + */ +function broadcastRemove(keys: string[]): void { + if (broadcastChannel && keys.length > 0) { + broadcastChannel.postMessage({type: 'remove', keys}); + } +} + +/** + * Broadcast CLEAR operation to other tabs. + */ +function broadcastClear(): void { + if (broadcastChannel) { + broadcastChannel.postMessage({type: 'clear'}); + } +} + +// --------------------------------------------------------------------------- +// Result helper +// --------------------------------------------------------------------------- + +function sendResult(id: string, data?: unknown, error?: string): void { + const msg: ResultMessage = {type: 'result', id}; + if (data !== undefined) { + msg.data = data; + } + if (error !== undefined) { + msg.error = error; + } + self.postMessage(msg); +} + +// --------------------------------------------------------------------------- +// Message handler (processes a single message; called serially by the queue) +// --------------------------------------------------------------------------- + +async function handleMessage(msg: WorkerMessage): Promise { + switch (msg.type) { + case 'init': { + // Dynamically import and initialize the chosen backend. + // If SQLite WASM fails (missing WASM binary, no OPFS, etc.) + // we automatically fall back to IndexedDB so operations never hang. + if (msg.backend === 'sqlite') { + try { + const sqliteModule = await import('./providers/SQLiteProvider/index.web'); + const sqliteProvider = sqliteModule.default; + + // SQLite needs async init (dynamic WASM import) + await sqliteModule.initAsync(); + provider = sqliteProvider; + } catch (sqliteError) { + console.warn('SQLite WASM init failed, falling back to IDB:', sqliteError); + const idbModule = await import('./providers/IDBKeyValProvider'); + provider = idbModule.default; + provider.init(); + } + } else { + const idbModule = await import('./providers/IDBKeyValProvider'); + provider = idbModule.default; + provider.init(); + } + + // Initialize BroadcastChannel for cross-tab sync + broadcastChannel = new BroadcastChannel(BROADCAST_CHANNEL_NAME); + sendResult(msg.id); + break; + } + + case 'getItem': { + const result = await provider!.getItem(msg.key); + sendResult(msg.id, result); + break; + } + + case 'multiGet': { + const results = await provider!.multiGet(msg.keys); + sendResult(msg.id, results); + break; + } + + case 'setItem': { + await provider!.setItem(msg.key, msg.value); + broadcastSet([[msg.key, msg.value]]); + sendResult(msg.id); + break; + } + + case 'multiSet': { + const pairs = msg.pairs as [string, unknown][]; + await provider!.multiSet(pairs); + broadcastSet(pairs); + sendResult(msg.id); + break; + } + + case 'multiMerge': { + const mergePairs = msg.pairs as [string, unknown, unknown[] | undefined][]; + await provider!.multiMerge(mergePairs); + // Broadcast raw patches (key + change value) so receiving tabs can fastMerge + broadcastMerge(mergePairs.map(([key, value]) => [key, value])); + sendResult(msg.id); + break; + } + + case 'getAllKeys': { + const keys = await provider!.getAllKeys(); + sendResult(msg.id, keys); + break; + } + + case 'removeItem': { + await provider!.removeItem(msg.key); + broadcastRemove([msg.key]); + sendResult(msg.id); + break; + } + + case 'removeItems': { + await provider!.removeItems(msg.keys); + broadcastRemove(msg.keys); + sendResult(msg.id); + break; + } + + case 'clear': { + await provider!.clear(); + broadcastClear(); + sendResult(msg.id); + break; + } + + case 'getDatabaseSize': { + const size = await provider!.getDatabaseSize(); + sendResult(msg.id, size); + break; + } + + default: + sendResult((msg as {id: string}).id, undefined, `Unknown message type: ${(msg as {type: string}).type}`); + } +} + +// --------------------------------------------------------------------------- +// Entry point: enqueue every incoming message and kick the serial processor +// --------------------------------------------------------------------------- + +self.onmessage = (event: MessageEvent) => { + messageQueue.push(event.data); + processQueue(); +}; + +export type {WorkerMessage, ResultMessage}; diff --git a/package-lock.json b/package-lock.json index d153c8b76..2a269b4fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "3.0.34", "license": "MIT", "dependencies": { + "@sqlite.org/sqlite-wasm": "^3.51.2-build6", "ascii-table": "0.0.9", "fast-equals": "^4.0.3", "lodash.bindall": "^4.4.0", @@ -36,6 +37,8 @@ "@typescript-eslint/eslint-plugin": "^8.51.0", "@typescript-eslint/parser": "^8.51.0", "@vercel/ncc": "0.38.1", + "@vitest/browser": "^4.0.18", + "@vitest/browser-playwright": "^4.0.18", "date-fns": "^4.1.0", "eslint": "^9.39.2", "eslint-config-expensify": "^2.0.102", @@ -51,6 +54,7 @@ "jest-environment-jsdom": "^29.7.0", "jsdoc-to-markdown": "^7.1.0", "nodemon": "^3.0.3", + "playwright": "^1.58.2", "prettier": "^2.8.8", "prop-types": "^15.7.2", "react": "18.2.0", @@ -61,9 +65,12 @@ "react-native-performance": "^5.1.0", "react-test-renderer": "18.2.0", "reassure": "1.4.0", + "tinybench": "^6.0.0", "ts-node": "^10.9.2", + "tsx": "^4.21.0", "type-fest": "^3.12.0", - "typescript": "^5.9.2" + "typescript": "^5.9.2", + "vitest": "^4.0.18" }, "engines": { "node": ">=20.19.5", @@ -76,7 +83,8 @@ "react-native-device-info": "^10.3.0", "react-native-nitro-modules": ">=0.27.2", "react-native-nitro-sqlite": "^9.2.0", - "react-native-performance": ">=5.1.0" + "react-native-performance": ">=5.1.0", + "react-native-worklets-core": "^1.6.2" }, "peerDependenciesMeta": { "idb-keyval": { @@ -139,7 +147,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -153,7 +160,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -168,7 +174,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -178,7 +183,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -211,6 +215,7 @@ "integrity": "sha512-fcdRcWahONYo+JRnJg1/AekOacGvKx12Gu0qXJXFi2WBqQA1i7+O5PaxRB7kxE/Op94dExnCiiar6T09pvdHpA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -228,7 +233,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -245,7 +249,6 @@ "version": "7.27.3", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.3" @@ -258,7 +261,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -275,7 +277,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -297,7 +298,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -315,7 +315,6 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", @@ -332,7 +331,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -342,7 +340,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.5", @@ -356,7 +353,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -370,7 +366,6 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -388,7 +383,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.1" @@ -401,7 +395,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -411,7 +404,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -429,7 +421,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.27.1", @@ -447,7 +438,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -461,7 +451,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -471,7 +460,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -481,7 +469,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -491,7 +478,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.1", @@ -506,7 +492,6 @@ "version": "7.27.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -520,7 +505,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" @@ -536,9 +520,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" @@ -554,9 +536,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -571,9 +551,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -588,9 +566,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", @@ -607,9 +583,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" @@ -626,7 +600,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", @@ -643,7 +616,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.27.1.tgz", "integrity": "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -660,7 +632,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", @@ -678,7 +649,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", @@ -696,9 +666,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" }, @@ -710,7 +678,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -723,7 +690,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -736,7 +702,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -749,7 +714,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -765,7 +729,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -778,7 +741,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.27.1.tgz", "integrity": "sha512-eBC/3KSekshx19+N40MzjWqJd7KTEdOoLesAfa4IDFI8eRz5a47i5Oszus6zG/cwIXN63YhgLOMSSNJx49sENg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -794,7 +756,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -810,9 +771,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -827,7 +786,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -843,7 +801,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -856,7 +813,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -869,7 +825,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -885,7 +840,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -898,7 +852,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -911,7 +864,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -924,7 +876,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -937,7 +888,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -950,7 +900,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -963,7 +912,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -979,7 +927,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -995,7 +942,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1011,9 +957,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1029,7 +973,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1045,7 +988,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1063,7 +1005,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -1081,9 +1022,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1098,7 +1037,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1114,7 +1052,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -1131,9 +1068,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" @@ -1149,7 +1084,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -1170,7 +1104,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1187,7 +1120,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1204,9 +1136,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1222,9 +1152,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1239,9 +1167,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1257,9 +1183,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1274,9 +1198,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0" @@ -1292,9 +1214,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1309,9 +1229,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1326,7 +1244,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1343,7 +1260,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1360,7 +1276,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", @@ -1378,9 +1293,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1395,7 +1308,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1411,7 +1323,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1427,9 +1338,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1444,9 +1353,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1462,7 +1369,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.27.1", @@ -1479,9 +1385,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", @@ -1499,9 +1403,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1517,7 +1419,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -1534,9 +1435,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1551,7 +1450,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1567,7 +1465,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1583,7 +1480,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", @@ -1603,9 +1499,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" @@ -1621,7 +1515,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1637,7 +1530,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1654,7 +1546,6 @@ "version": "7.27.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1670,7 +1561,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", @@ -1687,7 +1577,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -1705,9 +1594,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1722,7 +1609,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1738,7 +1624,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", @@ -1758,7 +1643,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1774,7 +1658,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1790,7 +1673,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1806,9 +1688,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1824,9 +1704,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1841,7 +1719,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.0.tgz", "integrity": "sha512-dGopk9nZrtCs2+nfIem25UuHyt5moSJamArzIoh9/vezUQPmYDOzjaHDCkAzuGJibCIkPup8rMT2+wYB6S73cA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -1862,7 +1739,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1878,7 +1754,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -1895,7 +1770,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1911,9 +1785,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1928,9 +1800,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1945,7 +1815,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", @@ -1965,9 +1834,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1982,9 +1849,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -2000,7 +1865,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", @@ -2017,9 +1881,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -2035,7 +1897,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", - "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -2121,7 +1982,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.27.1.tgz", "integrity": "sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2139,9 +1999,7 @@ "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -2155,7 +2013,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2175,7 +2032,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.27.1.tgz", "integrity": "sha512-K13lQpoV54LATKkzBpBAEu1GGSIRzxR9f4IN4V8DCDgiUMo2UDGagEZr3lPeVNJPLkWUi5JE4hCHKneVTwQlYQ==", - "dev": true, "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", @@ -2195,7 +2051,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^4.0.1", @@ -2209,7 +2064,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -2219,7 +2073,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -2230,7 +2083,6 @@ "version": "7.27.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2240,7 +2092,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -2255,7 +2106,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -2275,7 +2125,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -2294,7 +2143,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -2448,80 +2296,522 @@ "node": ">=20.11.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, + "optional": true, + "os": [ + "aix" + ], "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": ">=18" } }, - "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==", + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "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.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.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2815,7 +3105,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -2825,7 +3114,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -2842,7 +3130,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -2852,7 +3139,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -2866,7 +3152,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -2880,7 +3165,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -2893,7 +3177,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -2909,7 +3192,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -2922,7 +3204,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2932,7 +3213,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3008,7 +3288,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3" @@ -3021,7 +3300,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", @@ -3064,7 +3342,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -3142,7 +3419,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" @@ -3202,7 +3478,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", @@ -3229,7 +3504,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -3247,7 +3521,6 @@ "version": "0.3.12", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -3258,7 +3531,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -3268,7 +3540,6 @@ "version": "0.3.10", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3276,17 +3547,15 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", - "dev": true, + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.29", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3425,6 +3694,13 @@ "node": ">=14" } }, + "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/@react-native-community/eslint-config": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-3.2.0.tgz", @@ -3457,6 +3733,7 @@ "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -3492,6 +3769,7 @@ "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -3722,7 +4000,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.76.3.tgz", "integrity": "sha512-7Fnc3lzCFFpnoyL1egua6d/qUp0KiIpeSLbfOMln4nI2g2BMzyFHdPjJnpLV2NehmS0omOOkrfRqK5u1F/MXzA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3732,7 +4009,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.76.3.tgz", "integrity": "sha512-mZ7jmIIg4bUnxCqY3yTOkoHvvzsDyrZgfnIKiTGm5QACrsIGa5eT3pMFpMm2OpxGXRDrTMsYdPXE2rCyDX52VQ==", - "dev": true, "license": "MIT", "dependencies": { "@react-native/codegen": "0.76.3" @@ -3745,7 +4021,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.76.3.tgz", "integrity": "sha512-zi2nPlQf9q2fmfPyzwWEj6DU96v8ziWtEfG7CTAX2PG/Vjfsr94vn/wWrCdhBVvLRQ6Kvd/MFAuDYpxmQwIiVQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -3805,7 +4080,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.76.3.tgz", "integrity": "sha512-oJCH/jbYeGmFJql8/y76gqWCCd74pyug41yzYAjREso1Z7xL88JhDyKMvxEnfhSdMOZYVl479N80xFiXPy3ZYA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", @@ -3828,7 +4102,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.76.3.tgz", "integrity": "sha512-vgsLixHS24jR0d0QqPykBWFaC+V8x9cM3cs4oYXw3W199jgBNGP9MWcUJLazD2vzrT/lUTVBVg0rBeB+4XR6fg==", - "dev": true, "license": "MIT", "dependencies": { "@react-native/dev-middleware": "0.76.3", @@ -3859,7 +4132,6 @@ "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3872,7 +4144,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.76.3.tgz", "integrity": "sha512-pMHQ3NpPB28RxXciSvm2yD+uDx3pkhzfuWkc7VFgOduyzPSIr0zotUiOJzsAtrj8++bPbOsAraCeQhCqoOTWQw==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=18" @@ -3882,7 +4153,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.76.3.tgz", "integrity": "sha512-b+2IpW40z1/S5Jo5JKrWPmucYU/PzeGyGBZZ/SJvmRnBDaP3txb9yIqNZAII1EWsKNhedh8vyRO5PSuJ9Juqzw==", - "dev": true, "license": "MIT", "dependencies": { "@isaacs/ttlcache": "^1.4.1", @@ -3905,7 +4175,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -3915,14 +4184,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/@react-native/dev-middleware/node_modules/ws": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", - "dev": true, "license": "MIT", "dependencies": { "async-limiter": "~1.0.0" @@ -3932,7 +4199,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.76.3.tgz", "integrity": "sha512-t0aYZ8ND7+yc+yIm6Yp52bInneYpki6RSIFZ9/LMUzgMKvEB62ptt/7sfho9QkKHCNxE1DJSWIqLIGi/iHHkyg==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3942,7 +4208,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.76.3.tgz", "integrity": "sha512-pubJFArMMrdZiytH+W95KngcSQs+LsxOBsVHkwgMnpBfRUxXPMK4fudtBwWvhnwN76Oe+WhxSq7vOS5XgoPhmw==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3952,7 +4217,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.76.3.tgz", "integrity": "sha512-b2zQPXmW7avw/7zewc9nzMULPIAjsTwN03hskhxHUJH5pzUf7pIklB3FrgYPZrRhJgzHiNl3tOPu7vqiKzBYPg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -3971,7 +4235,6 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.76.3.tgz", "integrity": "sha512-Yrpmrh4IDEupUUM/dqVxhAN8QW1VEUR3Qrk2lzJC1jB2s46hDe0hrMP2vs12YJqlzshteOthjwXQlY0TgIzgbg==", - "dev": true, "license": "MIT" }, "node_modules/@react-native/polyfills": { @@ -3981,6 +4244,356 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -3992,14 +4605,12 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -4009,12 +4620,20 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@sqlite.org/sqlite-wasm": { + "version": "3.51.2-build6", + "resolved": "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.51.2-build6.tgz", + "integrity": "sha512-5ibsgipkqcLINZ5qNSp5KfrtL6KwiNVtwBksNO6zhTghhLmEf3/u1sPoAkgH5RzuLpMw7zi50IWgkZ0WhfqpaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=22" + } + }, "node_modules/@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", @@ -4022,6 +4641,13 @@ "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/@testing-library/react-native": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-13.2.0.tgz", @@ -4102,7 +4728,6 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -4116,7 +4741,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -4126,7 +4750,6 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -4137,12 +4760,29 @@ "version": "7.20.7", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } }, + "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": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "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/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -4154,7 +4794,6 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4164,14 +4803,12 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -4181,7 +4818,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -4251,6 +4887,7 @@ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" @@ -4267,8 +4904,8 @@ "version": "20.19.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.4.tgz", "integrity": "sha512-OP+We5WV8Xnbuvw0zC2m4qfB/BJvjyCwtNjhHdJxV1639SGSKrLmJkc3fMnp2Qy8nJyHp8RO6umxELN/dS1/EA==", - "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -4277,7 +4914,6 @@ "version": "1.3.12", "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.12.tgz", "integrity": "sha512-a0ToKlRVnUw3aXKQq2F+krxZKq7B8LEQijzPn5RdFAMatARD2JX9o8FBpMXOOrjob0uc13aN+V/AXniOXW4d9A==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4287,14 +4923,14 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.23", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -4322,7 +4958,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, "license": "MIT" }, "node_modules/@types/tough-cookie": { @@ -4343,7 +4978,6 @@ "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -4353,7 +4987,6 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -4401,6 +5034,7 @@ "integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.51.0", "@typescript-eslint/types": "8.51.0", @@ -4891,6 +5525,165 @@ "ncc": "dist/ncc/cli.js" } }, + "node_modules/@vitest/browser": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.0.18.tgz", + "integrity": "sha512-gVQqh7paBz3gC+ZdcCmNSWJMk70IUjDeVqi+5m5vYpEHsIwRgw3Y545jljtajhkekIpIp5Gg8oK7bctgY0E2Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/mocker": "4.0.18", + "@vitest/utils": "4.0.18", + "magic-string": "^0.30.21", + "pixelmatch": "7.1.0", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.0.3", + "ws": "^8.18.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.18" + } + }, + "node_modules/@vitest/browser-playwright": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.0.18.tgz", + "integrity": "sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/browser": "4.0.18", + "@vitest/mocker": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "4.0.18" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": false + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "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-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -4903,7 +5696,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" @@ -4916,7 +5708,6 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", @@ -4930,8 +5721,8 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5007,7 +5798,6 @@ "version": "1.4.10", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", - "dev": true, "license": "MIT" }, "node_modules/ansi-escape-sequences": { @@ -5066,7 +5856,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5076,7 +5865,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5099,7 +5887,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -5113,7 +5900,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -5350,7 +6136,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, "license": "MIT" }, "node_modules/ascii-table": { @@ -5359,11 +6144,20 @@ "integrity": "sha512-xpkr6sCDIYTPqzvjG8M3ncw1YOTaloWZOyrUmicoEifBEKzQzt+ooUpRpQ/AbOoJfO/p2ZKiyp79qHThzJDulQ==", "license": "MIT" }, + "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/ast-types": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz", "integrity": "sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -5393,7 +6187,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true, "license": "MIT" }, "node_modules/asynckit": { @@ -5443,7 +6236,6 @@ "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "dev": true, "license": "MIT", "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -5453,7 +6245,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", @@ -5475,7 +6266,6 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -5492,7 +6282,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", @@ -5509,7 +6298,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", @@ -5525,7 +6313,6 @@ "version": "0.4.14", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.7", @@ -5540,7 +6327,6 @@ "version": "0.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5", @@ -5554,7 +6340,6 @@ "version": "0.6.5", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" @@ -5567,7 +6352,6 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz", "integrity": "sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==", - "dev": true, "license": "MIT", "dependencies": { "hermes-parser": "0.25.1" @@ -5577,14 +6361,12 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, "license": "MIT" }, "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, "license": "MIT", "dependencies": { "hermes-estree": "0.25.1" @@ -5594,7 +6376,6 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-flow": "^7.12.1" @@ -5604,7 +6385,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -5631,7 +6411,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", @@ -5648,14 +6427,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -5706,7 +6483,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -5719,7 +6495,6 @@ "version": "4.25.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -5735,6 +6510,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", @@ -5752,7 +6528,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" @@ -5787,7 +6562,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, "license": "MIT" }, "node_modules/builtin-modules": { @@ -5882,7 +6656,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^2.0.0" @@ -5895,7 +6668,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -5905,7 +6677,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "dev": true, "license": "MIT", "dependencies": { "caller-callsite": "^2.0.0" @@ -5928,7 +6699,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5938,7 +6708,6 @@ "version": "1.0.30001727", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", - "dev": true, "funding": [ { "type": "opencollective", @@ -5968,11 +6737,20 @@ "node": ">= 10" } }, + "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/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -6044,7 +6822,6 @@ "version": "0.15.2", "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@types/node": "*", @@ -6063,7 +6840,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@types/node": "*", @@ -6078,7 +6854,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -6091,7 +6866,6 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, "funding": [ { "type": "github", @@ -6207,7 +6981,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -6222,7 +6995,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", @@ -6269,7 +7041,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -6282,7 +7053,6 @@ "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, "license": "MIT" }, "node_modules/combined-stream": { @@ -6397,7 +7167,6 @@ "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6427,7 +7196,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true, "license": "MIT" }, "node_modules/complex.js": { @@ -6448,7 +7216,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/config-master": { @@ -6482,7 +7249,6 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -6498,7 +7264,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -6508,21 +7273,18 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "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/core-js-compat": { "version": "3.44.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", "integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==", - "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.25.1" @@ -6536,7 +7298,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, "license": "MIT", "dependencies": { "import-fresh": "^2.0.0", @@ -6552,7 +7313,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -6562,7 +7322,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", - "dev": true, "license": "MIT", "dependencies": { "caller-path": "^2.0.0", @@ -6576,7 +7335,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -6590,7 +7348,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, "license": "MIT", "dependencies": { "error-ex": "^1.3.1", @@ -6604,7 +7361,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -6643,7 +7399,6 @@ "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", @@ -6685,7 +7440,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -6786,7 +7541,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6899,7 +7653,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -6909,7 +7662,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8", @@ -7036,14 +7788,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.180", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.180.tgz", "integrity": "sha512-ED+GEyEh3kYMwt2faNmgMB0b8O5qtATGgR4RmRsIp4T6p7B8vdMbIedYndnvZfsaXvSzegtpfqRMDNCjjiSduA==", - "dev": true, "license": "ISC" }, "node_modules/emittery": { @@ -7070,7 +7820,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -7093,7 +7842,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -7103,7 +7851,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "dev": true, "license": "MIT", "dependencies": { "stackframe": "^1.3.4" @@ -7226,6 +7973,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -7286,11 +8040,52 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7300,7 +8095,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, "license": "MIT" }, "node_modules/escape-latex": { @@ -7314,7 +8108,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -7351,6 +8144,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -8256,7 +9050,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -8302,11 +9095,20 @@ "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" @@ -8316,7 +9118,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -8326,7 +9127,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8336,7 +9136,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -8382,11 +9181,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", - "dev": true, "license": "Apache-2.0" }, "node_modules/fake-indexeddb": { @@ -8453,7 +9261,6 @@ "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, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -8496,7 +9303,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" @@ -8561,7 +9367,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -8574,7 +9379,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -8593,7 +9397,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -8603,14 +9406,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, "license": "MIT", "dependencies": { "commondir": "^1.0.1", @@ -8625,7 +9426,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -8638,7 +9438,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -8652,7 +9451,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^4.0.1", @@ -8666,7 +9464,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -8682,7 +9479,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -8695,7 +9491,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8705,7 +9500,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^3.0.0" @@ -8718,7 +9512,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -8802,14 +9595,12 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", - "dev": true, "license": "MIT" }, "node_modules/flow-parser": { "version": "0.275.0", "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.275.0.tgz", "integrity": "sha512-fHNwawoA2LM7FsxhU/1lTRGq9n6/Q8k861eHgN7GKtamYt9Qrxpg/ZSrev8o1WX7fQ2D3Gg3+uvYN15PmsG7Yw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -8896,7 +9687,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -8916,14 +9706,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "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, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -8938,7 +9726,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8979,7 +9766,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8989,7 +9775,6 @@ "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, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -9024,7 +9809,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -9048,7 +9832,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9093,7 +9876,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -9127,7 +9909,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -9138,7 +9919,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -9215,7 +9995,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -9264,7 +10043,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9332,7 +10110,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -9345,14 +10122,12 @@ "version": "0.23.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", - "dev": true, "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", - "dev": true, "license": "MIT", "dependencies": { "hermes-estree": "0.23.1" @@ -9409,7 +10184,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, "license": "MIT", "dependencies": { "depd": "2.0.0", @@ -9426,7 +10200,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -9465,7 +10238,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -9533,7 +10305,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", - "dev": true, "license": "MIT", "dependencies": { "queue": "6.0.2" @@ -9586,7 +10357,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -9607,7 +10377,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -9618,7 +10387,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -9640,7 +10408,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" @@ -9668,7 +10435,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -9793,7 +10559,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -9844,7 +10609,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9854,7 +10618,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" @@ -9896,7 +10659,6 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -9974,7 +10736,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -10001,7 +10762,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "license": "MIT", "dependencies": { "isobject": "^3.0.1" @@ -10069,7 +10829,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10179,7 +10938,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -10199,14 +10957,12 @@ "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/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10216,7 +10972,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -10343,6 +11098,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -10569,7 +11325,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", @@ -10587,7 +11342,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -10597,7 +11351,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -10653,7 +11406,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", @@ -10674,7 +11426,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -10707,7 +11458,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -10864,7 +11614,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -10882,7 +11631,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -10895,7 +11643,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -10913,7 +11660,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10946,7 +11692,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -10962,7 +11707,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10978,7 +11722,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -11008,21 +11751,18 @@ "version": "250231.0.0", "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-250231.0.0.tgz", "integrity": "sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/jsc-safe-url": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", - "dev": true, "license": "0BSD" }, "node_modules/jscodeshift": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.14.0.tgz", "integrity": "sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.13.16", @@ -11056,7 +11796,6 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, "license": "ISC", "dependencies": { "graceful-fs": "^4.1.11", @@ -11254,7 +11993,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -11274,7 +12012,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -11302,7 +12039,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -11341,7 +12077,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11391,7 +12126,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11415,7 +12149,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", - "dev": true, "license": "Apache-2.0", "dependencies": { "debug": "^2.6.9", @@ -11426,7 +12159,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -11436,7 +12168,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/lines-and-columns": { @@ -11503,7 +12234,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, "license": "MIT" }, "node_modules/lodash.merge": { @@ -11539,7 +12269,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", - "dev": true, "license": "MIT" }, "node_modules/lodash.transform": { @@ -11552,7 +12281,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -11565,12 +12293,21 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, + "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": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -11611,7 +12348,6 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" @@ -11623,6 +12359,7 @@ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -11663,7 +12400,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", - "dev": true, "license": "Apache-2.0" }, "node_modules/math-intrinsics": { @@ -11711,14 +12447,12 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "dev": true, "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -11735,7 +12469,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro/-/metro-0.81.5.tgz", "integrity": "sha512-YpFF0DDDpDVygeca2mAn7K0+us+XKmiGk4rIYMz/CRdjFoCGqAei/IQSpV0UrGfQbToSugpMQeQJveaWSH88Hg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", @@ -11790,7 +12523,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.81.5.tgz", "integrity": "sha512-oKCQuajU5srm+ZdDcFg86pG/U8hkSjBlkyFjz380SZ4TTIiI5F+OQB830i53D8hmqmcosa4wR/pnKv8y4Q3dLw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -11806,14 +12538,12 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, "license": "MIT" }, "node_modules/metro-babel-transformer/node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, "license": "MIT", "dependencies": { "hermes-estree": "0.25.1" @@ -11823,7 +12553,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.81.5.tgz", "integrity": "sha512-wOsXuEgmZMZ5DMPoz1pEDerjJ11AuMy9JifH4yNW7NmWS0ghCRqvDxk13LsElzLshey8C+my/tmXauXZ3OqZgg==", - "dev": true, "license": "MIT", "dependencies": { "exponential-backoff": "^3.1.1", @@ -11838,7 +12567,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.81.5.tgz", "integrity": "sha512-lGWnGVm1UwO8faRZ+LXQUesZSmP1LOg14OVR+KNPBip8kbMECbQJ8c10nGesw28uQT7AE0lwQThZPXlxDyCLKQ==", - "dev": true, "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -11851,7 +12579,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.81.5.tgz", "integrity": "sha512-oDRAzUvj6RNRxratFdcVAqtAsg+T3qcKrGdqGZFUdwzlFJdHGR9Z413sW583uD2ynsuOjA2QB6US8FdwiBdNKg==", - "dev": true, "license": "MIT", "dependencies": { "connect": "^3.6.5", @@ -11871,7 +12598,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.81.5.tgz", "integrity": "sha512-+2R0c8ByfV2N7CH5wpdIajCWa8escUFd8TukfoXyBq/vb6yTCsznoA25FhNXJ+MC/cz1L447Zj3vdUfCXIZBwg==", - "dev": true, "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", @@ -11886,7 +12612,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.81.5.tgz", "integrity": "sha512-mW1PKyiO3qZvjeeVjj1brhkmIotObA3/9jdbY1fQQYvEWM6Ml7bN/oJCRDGn2+bJRlG+J8pwyJ+DgdrM4BsKyg==", - "dev": true, "license": "MIT", "dependencies": { "debug": "^2.2.0", @@ -11907,7 +12632,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -11917,14 +12641,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/metro-minify-terser": { "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.81.5.tgz", "integrity": "sha512-/mn4AxjANnsSS3/Bb+zA1G5yIS5xygbbz/OuPaJYs0CPcZCaWt66D+65j4Ft/nJkffUxcwE9mk4ubpkl3rjgtw==", - "dev": true, "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", @@ -11938,7 +12660,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.81.5.tgz", "integrity": "sha512-6BX8Nq3g3go3FxcyXkVbWe7IgctjDTk6D9flq+P201DfHHQ28J+DWFpVelFcrNTn4tIfbP/Bw7u/0g2BGmeXfQ==", - "dev": true, "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -11951,7 +12672,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.5.tgz", "integrity": "sha512-M/Gf71ictUKP9+77dV/y8XlAWg7xl76uhU7ggYFUwEdOHHWPG6gLBr1iiK0BmTjPFH8yRo/xyqMli4s3oGorPQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", @@ -11965,7 +12685,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.5.tgz", "integrity": "sha512-Jz+CjvCKLNbJZYJTBeN3Kq9kIJf6b61MoLBdaOQZJ5Ajhw6Pf95Nn21XwA8BwfUYgajsi6IXsp/dTZsYJbN00Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.3", @@ -11987,7 +12706,6 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -11997,7 +12715,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.81.5.tgz", "integrity": "sha512-X3HV3n3D6FuTE11UWFICqHbFMdTavfO48nXsSpnNGFkUZBexffu0Xd+fYKp+DJLNaQr3S+lAs8q9CgtDTlRRuA==", - "dev": true, "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", @@ -12018,7 +12735,6 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12028,7 +12744,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.81.5.tgz", "integrity": "sha512-MmHhVx/1dJC94FN7m3oHgv5uOjKH8EX8pBeu1pnPMxbJrx6ZuIejO0k84zTSaQTZ8RxX1wqwzWBpXAWPjEX8mA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -12046,7 +12761,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.81.5.tgz", "integrity": "sha512-lUFyWVHa7lZFRSLJEv+m4jH8WrR5gU7VIjUlg4XmxQfV8ngY4V10ARKynLhMYPeQGl7Qvf+Ayg0eCZ272YZ4Mg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -12071,14 +12785,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true, "license": "MIT" }, "node_modules/metro/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -12088,14 +12800,12 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, "license": "MIT" }, "node_modules/metro/node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, "license": "MIT", "dependencies": { "hermes-estree": "0.25.1" @@ -12105,14 +12815,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/metro/node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -12122,7 +12830,6 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.3.0" @@ -12144,7 +12851,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -12158,7 +12864,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -12171,7 +12876,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, "license": "MIT", "bin": { "mime": "cli.js" @@ -12184,7 +12888,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12194,7 +12897,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -12207,7 +12909,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12243,7 +12944,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12263,7 +12963,6 @@ "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" @@ -12279,11 +12978,20 @@ "dev": true, "license": "MIT" }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "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, "license": "MIT" }, "node_modules/mz": { @@ -12298,6 +13006,25 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", @@ -12332,7 +13059,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -12342,14 +13068,12 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, "license": "MIT" }, "node_modules/node-dir": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", - "dev": true, "license": "MIT", "dependencies": { "minimatch": "^3.0.2" @@ -12362,7 +13086,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -12373,7 +13096,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -12386,7 +13108,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" @@ -12407,21 +13128,18 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, "license": "MIT" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "license": "MIT", "dependencies": { "tr46": "~0.0.3", @@ -12432,7 +13150,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -12442,14 +13159,12 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, "license": "MIT" }, "node_modules/nodemon": { @@ -12545,7 +13260,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12555,7 +13269,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -12568,7 +13281,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "dev": true, "license": "MIT" }, "node_modules/nwsapi": { @@ -12582,7 +13294,6 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.81.5.tgz", "integrity": "sha512-iNpbeXPLmaiT9I5g16gFFFjsF3sGxLpYG2EGP3dfFB4z+l9X60mp/yRzStHhMtuNt8qmf7Ww80nOPQHngHhnIQ==", - "dev": true, "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -12754,11 +13465,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -12771,7 +13492,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -12781,7 +13501,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -12797,7 +13516,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0", @@ -12882,7 +13600,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12991,7 +13708,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -13001,7 +13717,6 @@ "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, "license": "MIT", "engines": { "node": ">=8" @@ -13011,7 +13726,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13021,7 +13735,6 @@ "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" @@ -13031,7 +13744,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -13068,11 +13780,17 @@ "node": ">=8" } }, + "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/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -13081,6 +13799,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -13092,7 +13811,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -13102,12 +13820,24 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" } }, + "node_modules/pixelmatch": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz", + "integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==", + "dev": true, + "license": "ISC", + "dependencies": { + "pngjs": "^7.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -13177,6 +13907,53 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -13187,6 +13964,16 @@ "node": ">=4" } }, + "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": ">=14.19.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -13197,6 +13984,35 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -13213,6 +14029,7 @@ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin-prettier.js" }, @@ -13240,7 +14057,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", @@ -13255,7 +14071,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -13268,7 +14083,6 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "dev": true, "license": "MIT", "dependencies": { "asap": "~2.0.6" @@ -13375,7 +14189,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "dev": true, "license": "MIT", "dependencies": { "inherits": "~2.0.3" @@ -13406,7 +14219,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -13416,8 +14228,8 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -13429,7 +14241,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-5.3.2.tgz", "integrity": "sha512-crr9HkVrDiJ0A4zot89oS0Cgv0Oa4OG1Em4jit3P3ZxZSKPMYyMjfwMqgcJna9o625g8oN87rBm8SWWrSTBZxg==", - "dev": true, "license": "MIT", "dependencies": { "shell-quote": "^1.6.1", @@ -13440,7 +14251,6 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.3.0" @@ -13462,15 +14272,14 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, "license": "MIT" }, "node_modules/react-native": { "version": "0.76.3", "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.76.3.tgz", "integrity": "sha512-0TUhgmlouRNf6yuDIIAdbQl0g1VsONgCMsLs7Et64hjj5VLMCA7np+4dMrZvGZ3wRNqzgeyT9oWJsUm49AcwSQ==", - "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.6.3", "@react-native/assets-registry": "0.76.3", @@ -13544,6 +14353,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "peerDependencies": { "react": "*", "react-native": "*" @@ -13574,11 +14384,24 @@ "react-native": "*" } }, + "node_modules/react-native-worklets-core": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/react-native-worklets-core/-/react-native-worklets-core-1.6.2.tgz", + "integrity": "sha512-zw73JfL40ZL/OD2TOil1El4D9ZwS3l6AFPeFfUWXh+V2/dHN8i28jHX8QXlz5DYtAkR+Ju3U1h4yiaODi/igZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "string-hash-64": "^1.0.3" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native/node_modules/@react-native/virtualized-lists": { "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.76.3.tgz", "integrity": "sha512-wTGv9pVh3vAOWb29xFm+J9VRe9dUcUcb9FyaMLT/Hxa88W4wqa5ZMe1V9UvrrBiA1G5DKjv8/1ZcDsJhyugVKA==", - "dev": true, "license": "MIT", "dependencies": { "invariant": "^2.2.4", @@ -13602,7 +14425,6 @@ "version": "0.23.1", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.23.1.tgz", "integrity": "sha512-uNLD0tk2tLUjGFdmCk+u/3FEw2o+BAwW4g+z2QVlxJrzZYOOPADroEcNtTPt5lNiScctaUmnsTkVEnOwZUOLhA==", - "dev": true, "license": "MIT", "dependencies": { "hermes-parser": "0.23.1" @@ -13612,7 +14434,6 @@ "version": "0.24.0-canary-efb381bbf-20230505", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", "integrity": "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -13622,7 +14443,6 @@ "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -13635,7 +14455,6 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", - "dev": true, "license": "MIT", "dependencies": { "async-limiter": "~1.0.0" @@ -13645,7 +14464,6 @@ "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13671,6 +14489,7 @@ "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "react-is": "^18.2.0", "react-shallow-renderer": "^16.15.0", @@ -13710,7 +14529,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==", - "dev": true, "license": "BSD" }, "node_modules/reassure": { @@ -13734,7 +14552,6 @@ "version": "0.21.5", "resolved": "https://registry.npmjs.org/recast/-/recast-0.21.5.tgz", "integrity": "sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==", - "dev": true, "license": "MIT", "dependencies": { "ast-types": "0.15.2", @@ -13854,14 +14671,12 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", - "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -13874,7 +14689,6 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true, "license": "MIT" }, "node_modules/regexp-tree": { @@ -13925,7 +14739,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", - "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", @@ -13943,14 +14756,12 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, "license": "MIT" }, "node_modules/regjsparser": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" @@ -13963,7 +14774,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -13976,7 +14786,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -14003,7 +14812,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -14089,7 +14897,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -14101,6 +14908,51 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "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", @@ -14242,7 +15094,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "dev": true, "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", @@ -14256,7 +15107,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -14266,7 +15116,6 @@ "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -14291,7 +15140,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -14301,14 +15149,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, "license": "MIT" }, "node_modules/send/node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" @@ -14321,7 +15167,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -14331,7 +15176,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -14341,7 +15185,6 @@ "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dev": true, "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", @@ -14357,7 +15200,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -14416,7 +15258,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, "license": "ISC" }, "node_modules/sha.js": { @@ -14444,7 +15285,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, "license": "MIT", "dependencies": { "kind-of": "^6.0.2" @@ -14457,7 +15297,6 @@ "version": "2.0.0", "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" @@ -14470,7 +15309,6 @@ "version": "3.0.0", "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" @@ -14480,7 +15318,6 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -14565,11 +15402,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, "license": "ISC" }, "node_modules/simple-git": { @@ -14614,6 +15457,21 @@ "node": ">=10" } }, + "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": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -14625,7 +15483,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14667,6 +15524,15 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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, "license": "BSD-3-Clause", "engines": { @@ -14713,7 +15579,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/stable-hash-x": { @@ -14730,7 +15595,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -14743,24 +15607,28 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "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/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "dev": true, "license": "MIT" }, "node_modules/stacktrace-parser": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.7.1" @@ -14773,7 +15641,6 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -14783,12 +15650,18 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -14840,6 +15713,12 @@ "node": ">=0.10.0" } }, + "node_modules/string-hash-64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string-hash-64/-/string-hash-64-1.0.3.tgz", + "integrity": "sha512-D5OKWKvDhyVWWn2x5Y9b+37NUllks34q1dCDhk/vYcso9fmhs+Tl3KR/gE4v5UNj2UA35cnX4KdVVGkG1deKqw==", + "license": "MIT" + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -14865,7 +15744,6 @@ "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, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -14903,7 +15781,6 @@ "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, "license": "MIT" }, "node_modules/string.prototype.includes": { @@ -15023,7 +15900,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -15060,7 +15936,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -15109,7 +15984,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -15122,7 +15996,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -15172,7 +16045,6 @@ "version": "0.8.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", - "dev": true, "license": "MIT", "dependencies": { "rimraf": "~2.6.2" @@ -15193,7 +16065,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -15206,7 +16077,6 @@ "version": "5.43.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -15225,14 +16095,12 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, "license": "MIT" }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -15243,7 +16111,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -15258,7 +16125,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -15269,7 +16135,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -15332,7 +16197,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true, "license": "MIT" }, "node_modules/tiny-emitter": { @@ -15342,6 +16206,26 @@ "dev": true, "license": "MIT" }, + "node_modules/tinybench": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.0.0.tgz", + "integrity": "sha512-BWlWpVbbZXaYjRV0twGLNQO00Zj4HA/sjLOQP2IvzQqGwRGp+2kh7UU3ijyJ3ywFRogYDRbiHDMrUOfaMnN56g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -15359,11 +16243,20 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/to-buffer": { @@ -15385,7 +16278,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -15398,12 +16290,21 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.6" } }, + "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/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -15472,6 +16373,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -15560,7 +16462,6 @@ "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" }, "node_modules/tsutils": { @@ -15586,6 +16487,27 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -15613,7 +16535,6 @@ "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, "license": "MIT", "engines": { "node": ">=4" @@ -15884,6 +16805,7 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15969,14 +16891,12 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -15986,7 +16906,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", @@ -16000,7 +16919,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -16010,7 +16928,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -16030,7 +16947,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -16043,6 +16959,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "napi-postinstall": "^0.3.0" }, @@ -16075,7 +16992,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -16127,7 +17043,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -16165,11 +17080,172 @@ "node": ">=10.12.0" } }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.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 + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "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/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.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.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "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/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/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/vlq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", - "dev": true, "license": "MIT" }, "node_modules/w3c-xmlserializer": { @@ -16199,7 +17275,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" @@ -16232,7 +17307,6 @@ "version": "3.6.20", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", - "dev": true, "license": "MIT" }, "node_modules/whatwg-mimetype": { @@ -16263,7 +17337,6 @@ "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" @@ -16364,6 +17437,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -16409,7 +17499,6 @@ "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, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -16446,14 +17535,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -16513,7 +17600,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -16523,14 +17609,12 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -16549,7 +17633,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" diff --git a/package.json b/package.json index b7e428cea..dd2dadae9 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,11 @@ "test": "jest", "test:types": "npm run build && tsc --noEmit --project tsconfig.test.json", "perf-test": "npx reassure", + "bench": "vitest bench --run --config vitest.bench.config.ts", + "bench:compare": "./scripts/compareBenchmarks.sh", + "bench:save": "vitest bench --run --config vitest.bench.config.ts --outputJson .bench-baseline.json", + "bench:report": "./scripts/benchAndReport.sh", + "bench:report:compare": "./scripts/benchAndReport.sh --compare", "build": "tsc -p tsconfig.build.json", "build:watch": "nodemon --watch lib --ext js,json,ts,tsx --exec \"npm run build && npm pack\"", "prebuild:docs": "npm run build", @@ -43,6 +48,7 @@ "gh-actions-build": "./.github/scripts/buildActions.sh" }, "dependencies": { + "@sqlite.org/sqlite-wasm": "^3.51.2-build6", "ascii-table": "0.0.9", "fast-equals": "^4.0.3", "lodash.bindall": "^4.4.0", @@ -70,6 +76,8 @@ "@typescript-eslint/eslint-plugin": "^8.51.0", "@typescript-eslint/parser": "^8.51.0", "@vercel/ncc": "0.38.1", + "@vitest/browser": "^4.0.18", + "@vitest/browser-playwright": "^4.0.18", "date-fns": "^4.1.0", "eslint": "^9.39.2", "eslint-config-expensify": "^2.0.102", @@ -85,6 +93,7 @@ "jest-environment-jsdom": "^29.7.0", "jsdoc-to-markdown": "^7.1.0", "nodemon": "^3.0.3", + "playwright": "^1.58.2", "prettier": "^2.8.8", "prop-types": "^15.7.2", "react": "18.2.0", @@ -95,9 +104,12 @@ "react-native-performance": "^5.1.0", "react-test-renderer": "18.2.0", "reassure": "1.4.0", + "tinybench": "^6.0.0", "ts-node": "^10.9.2", + "tsx": "^4.21.0", "type-fest": "^3.12.0", - "typescript": "^5.9.2" + "typescript": "^5.9.2", + "vitest": "^4.0.18" }, "peerDependencies": { "idb-keyval": "^6.2.1", @@ -106,7 +118,8 @@ "react-native-device-info": "^10.3.0", "react-native-nitro-modules": ">=0.27.2", "react-native-nitro-sqlite": "^9.2.0", - "react-native-performance": ">=5.1.0" + "react-native-performance": ">=5.1.0", + "react-native-worklets-core": "^1.6.2" }, "peerDependenciesMeta": { "idb-keyval": { diff --git a/scripts/benchAndReport.sh b/scripts/benchAndReport.sh new file mode 100755 index 000000000..83d361ab8 --- /dev/null +++ b/scripts/benchAndReport.sh @@ -0,0 +1,247 @@ +#!/bin/bash +# +# benchAndReport.sh — Run benchmarks, generate a color-coded HTML report, and open it. +# +# This script supports three modes: +# +# 1. Single run (current code only): +# ./scripts/benchAndReport.sh +# +# 2. Compare current branch vs a base branch: +# ./scripts/benchAndReport.sh --compare main +# +# 3. Multi-config comparison (e.g. swapping storage providers): +# Provide one or more --run flags with a label and an optional setup command. +# ./scripts/benchAndReport.sh \ +# --run "Baseline" \ +# --run "DM+SQLite" \ +# --run "DM+IDB:printf 'import W from \"../providers/IDBKeyValProvider\";\nexport default W;\n' > lib/storage/platforms/index.ts" +# +# Options: +# --compare Compare current branch against +# --run "