From a9bba1481753b152794768259a9987e51f8f98f7 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 09:43:56 +0100 Subject: [PATCH 01/15] sync(common-v8): port 7e0d6897 custom DisposableStack polyfills Source upstream commit: 7e0d6897615c493e1154a5670f32a1686f9ec1ce Port scope: adapted (keeps fork dependency versions, adds runtime-compatible test assertions) --- bun.lock | 5 - packages/common/package.json | 1 - packages/common/src/Polyfills.ts | 444 ++++++- packages/common/test/Polyfills.test.ts | 1468 ++++++++++++++++++++++++ packages/common/test/_browserSetup.ts | 5 +- 5 files changed, 1911 insertions(+), 12 deletions(-) create mode 100644 packages/common/test/Polyfills.test.ts diff --git a/bun.lock b/bun.lock index 4a48d97cc..79f964852 100644 --- a/bun.lock +++ b/bun.lock @@ -294,7 +294,6 @@ "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", "@scure/bip39": "^2.0.1", - "disposablestack": "^1.1.7", "kysely": "^0.28.11", "msgpackr": "^1.11.8", "zod": "^4.3.6", @@ -2133,8 +2132,6 @@ "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], - "disposablestack": ["disposablestack@1.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.0.7", "suppressed-error": "^1.0.3" } }, "sha512-UmyM57A8fTz5Hn4pYO/q2YdQ7fApPmxT3T5eA3Igr4UnUZ/HY6zEWSUVR7QT6kiM4udOyljC8Ag2jn7DnaSUqA=="], - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], "dmg-builder": ["dmg-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg=="], @@ -3511,8 +3508,6 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "suppressed-error": ["suppressed-error@1.0.3", "", { "dependencies": { "define-data-property": "^1.1.1", "define-properties": "^1.2.1", "es-abstract": "^1.22.3", "es-errors": "^1.1.0", "function-bind": "^1.1.2", "globalthis": "^1.0.3", "has-property-descriptors": "^1.0.1", "set-function-name": "^2.0.1" } }, "sha512-6+ZiCVUmDLFRyYRswTrDTYWaM/IT01W/cqQBLnnyg8T0njVrWj3tP+EXFevXk6qK61yDXnmZsOFVzFfYoUy/KA=="], - "svelte": ["svelte@5.53.6", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.3", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-lP5DGF3oDDI9fhHcSpaBiJEkFLuS16h92DhM1L5K1lFm0WjOmUh1i2sNkBBk8rkxJRpob0dBE75jRfUzGZUOGA=="], "svelte-check": ["svelte-check@4.4.4", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-F1pGqXc710Oi/wTI4d/x7d6lgPwwfx1U6w3Q35n4xsC2e8C/yN2sM1+mWxjlMcpAfWucjlq4vPi+P4FZ8a14sQ=="], diff --git a/packages/common/package.json b/packages/common/package.json index 7248b222b..f6d8590fa 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -56,7 +56,6 @@ "@noble/ciphers": "^2.1.1", "@noble/hashes": "^2.0.1", "@scure/bip39": "^2.0.1", - "disposablestack": "^1.1.7", "kysely": "^0.28.11", "msgpackr": "^1.11.8", "zod": "^4.3.6" diff --git a/packages/common/src/Polyfills.ts b/packages/common/src/Polyfills.ts index b1889772e..6dcbc7c4e 100644 --- a/packages/common/src/Polyfills.ts +++ b/packages/common/src/Polyfills.ts @@ -4,9 +4,6 @@ * @module */ -import "disposablestack/auto"; -import { lazyVoid } from "./Function.js"; - /** * Installs polyfills required by `@evolu/common`. * @@ -25,5 +22,444 @@ import { lazyVoid } from "./Function.js"; * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Resource_management * @see https://github.com/es-shims/DisposableStack + * @see https://github.com/es-shims/DisposableStack/issues/9 */ -export const installPolyfills = lazyVoid; +export const installPolyfills = (): void => { + /** + * This module intentionally owns `DisposableStack` and `AsyncDisposableStack` + * polyfills instead of depending on `es-shims/DisposableStack` at runtime. + * + * Evolu originally used the upstream package, but WebKit hit a known async + * disposal completion bug (`completion["?"]` crash, see issue #9). The local + * implementation applies the fix and keeps behavior deterministic across + * runtimes used by Evolu. + * + * Conformance is validated by tests that combine upstream-style and test262 + * parity cases with Evolu-specific regressions. Those tests run against + * native Node.js behavior and against this polyfill path in browser projects, + * including WebKit. + */ + installDisposableStack(); +}; + +interface DisposableResource { + readonly dispose: () => void; +} + +interface AsyncDisposableResource { + readonly dispose: () => Promise; +} + +/** Installs `DisposableStack`-related polyfills missing from the runtime. */ +const installDisposableStack = (): void => { + installSuppressedError(); + + const symbolDispose = getOrInstallSymbol("dispose", "Symbol.dispose"); + const symbolAsyncDispose = getOrInstallSymbol( + "asyncDispose", + "Symbol.asyncDispose", + ); + + if (typeof globalThis.DisposableStack !== "function") { + defineGlobalValue( + globalThis, + "DisposableStack", + createDisposableStackPolyfill(symbolDispose), + ); + } + + if (typeof globalThis.AsyncDisposableStack !== "function") { + defineGlobalValue( + globalThis, + "AsyncDisposableStack", + createAsyncDisposableStackPolyfill(symbolDispose, symbolAsyncDispose), + ); + } +}; + +type SymbolWithDisposable = SymbolConstructor & { + dispose?: symbol; + asyncDispose?: symbol; +}; + +const suppressedErrorMessage = "An error was suppressed during disposal."; + +const disposedMessage = (className: string, method: string): string => + `Cannot call ${className}.prototype.${method} on an already-disposed DisposableStack`; + +const defineGlobalValue = ( + target: object, + key: PropertyKey, + value: unknown, +): void => { + Object.defineProperty(target, key, { + configurable: true, + enumerable: false, + writable: true, + value, + }); +}; + +const defineMethodAlias = ( + target: object, + alias: symbol, + methodName: string, +): void => { + defineGlobalValue( + target, + alias, + Object.getOwnPropertyDescriptor(target, methodName)?.value, + ); +}; + +const throwIfDisposed = (disposed: boolean, message: string): void => { + if (disposed) { + throw new ReferenceError(message); + } +}; + +const appendDisposeError = ( + currentError: unknown, + previousError: unknown, +): unknown => + new globalThis.SuppressedError( + currentError, + previousError, + suppressedErrorMessage, + ); + +const assertObjectOrFunction = (value: unknown): object => { + if ( + (typeof value !== "object" || value === null) && + typeof value !== "function" + ) { + throw new TypeError("Disposable value must be an object or function."); + } + + return value; +}; + +const getMethod = ( + value: object, + key: symbol, +): ((this: unknown) => unknown) | undefined => { + const method = (value as Record)[key]; + if (method === undefined) return undefined; + if (typeof method !== "function") { + throw new TypeError("Disposable method must be a function."); + } + return method as (this: unknown) => unknown; +}; + +const getOrInstallSymbol = ( + key: "dispose" | "asyncDispose", + description: string, +): symbol => { + const SymbolCtor = globalThis.Symbol as SymbolWithDisposable; + const installedValue = Object.getOwnPropertyDescriptor(SymbolCtor, key) + ?.value as unknown; + const installed = + typeof installedValue === "symbol" ? installedValue : undefined; + if (installed != null) return installed; + + const symbol = Symbol(description); + Object.defineProperty(SymbolCtor, key, { + configurable: false, + enumerable: false, + writable: false, + value: symbol, + }); + return symbol; +}; + +const installSuppressedError = (): void => { + if (typeof globalThis.SuppressedError === "function") return; + + class SuppressedErrorPolyfill + extends Error + implements globalThis.SuppressedError + { + readonly error: unknown; + readonly suppressed: unknown; + + constructor(error: unknown, suppressed: unknown, message?: string) { + super(message ?? suppressedErrorMessage); + this.name = "SuppressedError"; + this.error = error; + this.suppressed = suppressed; + } + } + + defineGlobalValue(globalThis, "SuppressedError", SuppressedErrorPolyfill); +}; + +const createDisposableStackPolyfill = ( + symbolDispose: symbol, +): (new () => DisposableStack) => { + class DisposableStackPolyfill implements DisposableStack { + #disposed = false; + #resources: Array = []; + + declare readonly [Symbol.toStringTag]: "DisposableStack"; + declare [Symbol.dispose]: () => void; + + get disposed(): boolean { + return this.#disposed; + } + + use(value: T): T { + throwIfDisposed( + this.#disposed, + disposedMessage("DisposableStack", "use"), + ); + if (value == null) return value; + + const target = assertObjectOrFunction(value); + const method = getMethod(target, symbolDispose); + if (method == null) { + throw new TypeError("Resource does not implement Symbol.dispose."); + } + + this.#resources.push({ + dispose: () => { + method.call(target); + }, + }); + + return value; + } + + adopt(value: T, onDispose: (value: T) => void): T { + throwIfDisposed( + this.#disposed, + disposedMessage("DisposableStack", "adopt"), + ); + if (typeof onDispose !== "function") { + throw new TypeError("onDispose must be a function."); + } + + this.#resources.push({ + dispose: () => { + onDispose(value); + }, + }); + + return value; + } + + defer(onDispose: () => void): void { + throwIfDisposed( + this.#disposed, + disposedMessage("DisposableStack", "defer"), + ); + if (typeof onDispose !== "function") { + throw new TypeError("onDispose must be a function."); + } + + this.#resources.push({ + dispose: () => { + onDispose(); + }, + }); + } + + move(): DisposableStack { + throwIfDisposed( + this.#disposed, + disposedMessage("DisposableStack", "move"), + ); + + const moved = new DisposableStackPolyfill(); + moved.#resources = this.#resources; + + this.#resources = []; + this.#disposed = true; + + return moved; + } + + dispose(): void { + if (this.#disposed) return; + + this.#disposed = true; + const resources = this.#resources; + this.#resources = []; + + let completionError: unknown; + let hasCompletionError = false; + + for (let i = resources.length - 1; i >= 0; i--) { + try { + resources[i].dispose(); + } catch (error) { + completionError = hasCompletionError + ? appendDisposeError(error, completionError) + : error; + hasCompletionError = true; + } + } + + if (hasCompletionError) { + throw completionError; + } + } + } + + defineMethodAlias( + DisposableStackPolyfill.prototype, + symbolDispose, + "dispose", + ); + + Object.defineProperty(DisposableStackPolyfill.prototype, Symbol.toStringTag, { + configurable: true, + enumerable: false, + writable: false, + value: "DisposableStack", + }); + + return DisposableStackPolyfill; +}; + +const createAsyncDisposableStackPolyfill = ( + symbolDispose: symbol, + symbolAsyncDispose: symbol, +): (new () => AsyncDisposableStack) => { + class AsyncDisposableStackPolyfill implements AsyncDisposableStack { + #disposed = false; + #resources: Array = []; + + declare readonly [Symbol.toStringTag]: "AsyncDisposableStack"; + declare [Symbol.asyncDispose]: () => Promise; + + get disposed(): boolean { + return this.#disposed; + } + + use(value: T): T { + throwIfDisposed( + this.#disposed, + disposedMessage("AsyncDisposableStack", "use"), + ); + if (value == null) return value; + + const target = assertObjectOrFunction(value); + const asyncMethod = getMethod(target, symbolAsyncDispose); + + if (asyncMethod != null) { + this.#resources.push({ + dispose: async () => { + await asyncMethod.call(target); + }, + }); + return value; + } + + const syncMethod = getMethod(target, symbolDispose); + + if (syncMethod != null) { + this.#resources.push({ + dispose: () => + Promise.resolve().then(() => { + syncMethod.call(target); + }), + }); + return value; + } + + throw new TypeError( + "Resource does not implement Symbol.asyncDispose or Symbol.dispose.", + ); + } + + adopt(value: T, onDisposeAsync: (value: T) => void | Promise): T { + throwIfDisposed( + this.#disposed, + disposedMessage("AsyncDisposableStack", "adopt"), + ); + if (typeof onDisposeAsync !== "function") { + throw new TypeError("onDisposeAsync must be a function."); + } + + this.#resources.push({ + dispose: () => Promise.resolve().then(() => onDisposeAsync(value)), + }); + + return value; + } + + defer(onDisposeAsync: () => void | Promise): void { + throwIfDisposed( + this.#disposed, + disposedMessage("AsyncDisposableStack", "defer"), + ); + if (typeof onDisposeAsync !== "function") { + throw new TypeError("onDisposeAsync must be a function."); + } + + this.#resources.push({ + dispose: () => Promise.resolve().then(() => onDisposeAsync()), + }); + } + + move(): AsyncDisposableStack { + throwIfDisposed( + this.#disposed, + disposedMessage("AsyncDisposableStack", "move"), + ); + + const moved = new AsyncDisposableStackPolyfill(); + moved.#resources = this.#resources; + + this.#resources = []; + this.#disposed = true; + + return moved; + } + + async disposeAsync(): Promise { + if (this.#disposed) return; + + this.#disposed = true; + const resources = this.#resources; + this.#resources = []; + + let completionError: unknown; + let hasCompletionError = false; + + for (let i = resources.length - 1; i >= 0; i--) { + try { + await resources[i].dispose(); + } catch (error) { + completionError = hasCompletionError + ? appendDisposeError(error, completionError) + : error; + hasCompletionError = true; + } + } + + if (hasCompletionError) { + throw completionError; + } + } + } + + defineMethodAlias( + AsyncDisposableStackPolyfill.prototype, + symbolAsyncDispose, + "disposeAsync", + ); + + Object.defineProperty( + AsyncDisposableStackPolyfill.prototype, + Symbol.toStringTag, + { + configurable: true, + enumerable: false, + writable: false, + value: "AsyncDisposableStack", + }, + ); + + return AsyncDisposableStackPolyfill; +}; diff --git a/packages/common/test/Polyfills.test.ts b/packages/common/test/Polyfills.test.ts new file mode 100644 index 000000000..0a1d1f8be --- /dev/null +++ b/packages/common/test/Polyfills.test.ts @@ -0,0 +1,1468 @@ +/** + * DisposableStack and AsyncDisposableStack conformance tests. + * + * Test strategy: + * + * - Port upstream `es-shims/DisposableStack` and test262-style behavior checks. + * - Add Evolu-specific regressions, including the WebKit async completion failure + * tracked in `es-shims/DisposableStack#9`. + * - Validate parity against native Node.js implementations. + * - Validate the owned polyfill implementation in browser projects, including + * WebKit. + */ +import { afterEach, beforeEach, describe, expect, test } from "vitest"; +import { installPolyfills } from "../src/Polyfills.js"; + +const isNodeRuntime = + ( + globalThis as { + readonly process?: { + readonly versions?: { + readonly node?: string; + }; + }; + } + ).process?.versions?.node != null; + +const isNativeDisposableStackImplementation = isNodeRuntime; + +const assertNativeDisposableStackImplementation = (): void => { + if ( + typeof globalThis.DisposableStack === "function" && + typeof globalThis.AsyncDisposableStack === "function" && + typeof globalThis.SuppressedError === "function" && + typeof Symbol.dispose === "symbol" && + typeof Symbol.asyncDispose === "symbol" + ) { + return; + } + + throw new Error( + "Node runtime requires native DisposableStack, AsyncDisposableStack, SuppressedError, Symbol.dispose, and Symbol.asyncDispose.", + ); +}; + +if (isNativeDisposableStackImplementation) { + assertNativeDisposableStackImplementation(); +} + +type TrackedGlobalKey = + | "Symbol" + | "DisposableStack" + | "AsyncDisposableStack" + | "SuppressedError"; + +type GlobalDescriptorSnapshot = Readonly< + Record +>; + +const trackedGlobalKeys: ReadonlyArray = [ + "Symbol", + "DisposableStack", + "AsyncDisposableStack", + "SuppressedError", +]; + +const readGlobalDescriptorSnapshot = (): GlobalDescriptorSnapshot => ({ + Symbol: Object.getOwnPropertyDescriptor(globalThis, "Symbol"), + DisposableStack: Object.getOwnPropertyDescriptor( + globalThis, + "DisposableStack", + ), + AsyncDisposableStack: Object.getOwnPropertyDescriptor( + globalThis, + "AsyncDisposableStack", + ), + SuppressedError: Object.getOwnPropertyDescriptor( + globalThis, + "SuppressedError", + ), +}); + +const deleteTrackedGlobal = (key: TrackedGlobalKey): void => { + switch (key) { + case "Symbol": + delete (globalThis as { Symbol?: SymbolConstructor }).Symbol; + return; + case "DisposableStack": + delete (globalThis as { DisposableStack?: typeof DisposableStack }) + .DisposableStack; + return; + case "AsyncDisposableStack": + delete ( + globalThis as { + AsyncDisposableStack?: typeof AsyncDisposableStack; + } + ).AsyncDisposableStack; + return; + case "SuppressedError": + delete (globalThis as { SuppressedError?: typeof SuppressedError }) + .SuppressedError; + return; + } +}; + +const restoreGlobalDescriptorSnapshot = ( + snapshot: GlobalDescriptorSnapshot, +): void => { + for (const key of trackedGlobalKeys) { + const descriptor = snapshot[key]; + if (descriptor == null) { + deleteTrackedGlobal(key); + continue; + } + + Object.defineProperty(globalThis, key, descriptor); + } +}; + +const deleteGlobalIfConfigurable = (key: TrackedGlobalKey): void => { + const descriptor = Object.getOwnPropertyDescriptor(globalThis, key); + if (descriptor == null) return; + + if (descriptor.configurable) { + deleteTrackedGlobal(key); + return; + } + + if (!descriptor.writable) return; + + Object.defineProperty(globalThis, key, { + ...descriptor, + value: undefined, + }); +}; + +const installOwnedDisposableImplementation = (): void => { + if (isNativeDisposableStackImplementation) return; + + deleteGlobalIfConfigurable("DisposableStack"); + deleteGlobalIfConfigurable("AsyncDisposableStack"); + deleteGlobalIfConfigurable("SuppressedError"); + installPolyfills(); +}; + +const createSymbolWithoutDisposableStatics = (): SymbolConstructor => { + const nativeSymbol = globalThis.Symbol; + + const wrappedSymbol = ((description?: string) => + nativeSymbol(description)) as unknown as SymbolConstructor; + + for (const key of Reflect.ownKeys(nativeSymbol)) { + if (key === "dispose" || key === "asyncDispose") continue; + if (Object.hasOwn(wrappedSymbol, key)) continue; + + const descriptor = Object.getOwnPropertyDescriptor(nativeSymbol, key); + if (descriptor == null) continue; + + Object.defineProperty(wrappedSymbol, key, descriptor); + } + + return wrappedSymbol; +}; + +const nonNullPrimitives: ReadonlyArray = [ + true, + false, + 0, + 1, + 1n, + Number.NaN, + Number.POSITIVE_INFINITY, + "", + "value", + Symbol("local-test-symbol"), +]; + +const nonFunctions: ReadonlyArray = [ + ...nonNullPrimitives, + null, + undefined, + {}, + [], +]; + +const expectThrownNonErrorValue = (error: unknown, expected: unknown): void => { + expect(error).toBe(expected); +}; + +describe("installPolyfills Symbol statics", () => { + let globalSnapshot: GlobalDescriptorSnapshot; + + beforeEach(() => { + globalSnapshot = readGlobalDescriptorSnapshot(); + }); + + afterEach(() => { + restoreGlobalDescriptorSnapshot(globalSnapshot); + }); + + test("installs missing Symbol.dispose and Symbol.asyncDispose with immutable descriptors", () => { + const wrappedSymbol = createSymbolWithoutDisposableStatics(); + + Object.defineProperty(globalThis, "Symbol", { + configurable: true, + enumerable: false, + writable: true, + value: wrappedSymbol, + }); + + installPolyfills(); + + expect(typeof Symbol.dispose).toBe("symbol"); + expect(typeof Symbol.asyncDispose).toBe("symbol"); + + const disposeDescriptor = Object.getOwnPropertyDescriptor( + Symbol, + "dispose", + ); + const asyncDisposeDescriptor = Object.getOwnPropertyDescriptor( + Symbol, + "asyncDispose", + ); + + expect(disposeDescriptor?.configurable).toBe(false); + expect(disposeDescriptor?.enumerable).toBe(false); + expect(disposeDescriptor?.writable).toBe(false); + expect(asyncDisposeDescriptor?.configurable).toBe(false); + expect(asyncDisposeDescriptor?.enumerable).toBe(false); + expect(asyncDisposeDescriptor?.writable).toBe(false); + }); +}); + +const describeInstallPolyfills = isNativeDisposableStackImplementation + ? describe.skip + : describe; + +describeInstallPolyfills("installPolyfills", () => { + let globalSnapshot: GlobalDescriptorSnapshot; + + beforeEach(() => { + globalSnapshot = readGlobalDescriptorSnapshot(); + }); + + afterEach(() => { + restoreGlobalDescriptorSnapshot(globalSnapshot); + }); + + test("installs DisposableStack, AsyncDisposableStack, and SuppressedError", () => { + installOwnedDisposableImplementation(); + + expect(typeof globalThis.DisposableStack).toBe("function"); + expect(typeof globalThis.AsyncDisposableStack).toBe("function"); + expect(typeof globalThis.SuppressedError).toBe("function"); + + const disposableStack = new globalThis.DisposableStack(); + const asyncDisposableStack = new globalThis.AsyncDisposableStack(); + + expect(typeof disposableStack[Symbol.dispose]).toBe("function"); + expect(typeof asyncDisposableStack[Symbol.asyncDispose]).toBe("function"); + + disposableStack[Symbol.dispose](); + void asyncDisposableStack[Symbol.asyncDispose](); + }); + + test("installs Symbol.dispose and Symbol.asyncDispose when missing", () => { + const wrappedSymbol = createSymbolWithoutDisposableStatics(); + + Object.defineProperty(globalThis, "Symbol", { + configurable: true, + enumerable: false, + writable: true, + value: wrappedSymbol, + }); + + installOwnedDisposableImplementation(); + + expect(typeof Symbol.dispose).toBe("symbol"); + expect(typeof Symbol.asyncDispose).toBe("symbol"); + + const disposeDescriptor = Object.getOwnPropertyDescriptor( + Symbol, + "dispose", + ); + const asyncDisposeDescriptor = Object.getOwnPropertyDescriptor( + Symbol, + "asyncDispose", + ); + + expect(disposeDescriptor?.configurable).toBe(false); + expect(disposeDescriptor?.enumerable).toBe(false); + expect(disposeDescriptor?.writable).toBe(false); + expect(asyncDisposeDescriptor?.configurable).toBe(false); + expect(asyncDisposeDescriptor?.enumerable).toBe(false); + expect(asyncDisposeDescriptor?.writable).toBe(false); + + const disposableStack = new globalThis.DisposableStack(); + const asyncDisposableStack = new globalThis.AsyncDisposableStack(); + + expect(typeof disposableStack[Symbol.dispose]).toBe("function"); + expect(typeof asyncDisposableStack[Symbol.asyncDispose]).toBe("function"); + + expect(Symbol.keyFor(Symbol.dispose)).toBeUndefined(); + expect(Symbol.keyFor(Symbol.asyncDispose)).toBeUndefined(); + }); + + test("does not override existing globals", () => { + class ExistingDisposableStack implements DisposableStack { + disposed = false; + readonly [Symbol.toStringTag] = "DisposableStack"; + + use(value: T): T { + return value; + } + adopt(value: T, _onDispose: (value: T) => void): T { + return value; + } + defer(_onDispose: () => void): void { + return; + } + move(): DisposableStack { + return this; + } + dispose(): void { + this.disposed = true; + } + [Symbol.dispose](): void { + this.dispose(); + } + } + + class ExistingAsyncDisposableStack implements AsyncDisposableStack { + disposed = false; + readonly [Symbol.toStringTag] = "AsyncDisposableStack"; + + use(value: T): T { + return value; + } + adopt( + value: T, + _onDisposeAsync: (value: T) => void | Promise, + ): T { + return value; + } + defer(_onDisposeAsync: () => void | Promise): void { + return; + } + move(): AsyncDisposableStack { + return this; + } + disposeAsync(): Promise { + this.disposed = true; + return Promise.resolve(); + } + [Symbol.asyncDispose](): Promise { + return this.disposeAsync(); + } + } + + class ExistingSuppressedError extends Error { + readonly error: unknown; + readonly suppressed: unknown; + + constructor(error: unknown, suppressed: unknown, message = "existing") { + super(message); + this.error = error; + this.suppressed = suppressed; + } + } + + Object.defineProperty(globalThis, "DisposableStack", { + configurable: true, + enumerable: false, + writable: true, + value: ExistingDisposableStack, + }); + Object.defineProperty(globalThis, "AsyncDisposableStack", { + configurable: true, + enumerable: false, + writable: true, + value: ExistingAsyncDisposableStack, + }); + Object.defineProperty(globalThis, "SuppressedError", { + configurable: true, + enumerable: false, + writable: true, + value: ExistingSuppressedError, + }); + + installPolyfills(); + + expect(globalThis.DisposableStack).toBe(ExistingDisposableStack); + expect(globalThis.AsyncDisposableStack).toBe(ExistingAsyncDisposableStack); + expect(globalThis.SuppressedError).toBe(ExistingSuppressedError); + }); + + test("keeps explicit SuppressedError message", () => { + installOwnedDisposableImplementation(); + + const suppressedError = new globalThis.SuppressedError( + new Error("error"), + new Error("suppressed"), + "custom message", + ); + + expect(suppressedError.message).toBe("custom message"); + }); + + test("uses default SuppressedError message when omitted", () => { + installOwnedDisposableImplementation(); + + const suppressedError = new globalThis.SuppressedError( + new Error("error"), + new Error("suppressed"), + ); + + expect(suppressedError.message).toBe( + "An error was suppressed during disposal.", + ); + }); +}); + +describe("DisposableStack behavior", () => { + let globalSnapshot: GlobalDescriptorSnapshot; + + beforeEach(() => { + globalSnapshot = readGlobalDescriptorSnapshot(); + installOwnedDisposableImplementation(); + }); + + afterEach(() => { + restoreGlobalDescriptorSnapshot(globalSnapshot); + }); + + test("constructor creates DisposableStack instances and requires new", () => { + const DisposableStackCtor = globalThis.DisposableStack; + + expect(typeof DisposableStackCtor).toBe("function"); + + const instance = new DisposableStackCtor(); + expect(typeof instance).toBe("object"); + expect(instance).toBeInstanceOf(DisposableStackCtor); + + expect(() => + ( + DisposableStackCtor as unknown as (...args: Array) => unknown + )(), + ).toThrow(TypeError); + + expect(DisposableStackCtor.prototype.constructor).toBe(DisposableStackCtor); + }); + + test("disposed is a prototype accessor", () => { + const stack = new globalThis.DisposableStack(); + + expect(Object.hasOwn(stack, "disposed")).toBe(false); + + const descriptor = Object.getOwnPropertyDescriptor( + globalThis.DisposableStack.prototype, + "disposed", + ); + + expect(descriptor).toBeDefined(); + expect(descriptor?.configurable).toBe(true); + expect(descriptor?.enumerable).toBe(false); + expect(typeof descriptor?.get).toBe("function"); + expect(stack.disposed).toBe(false); + + stack.dispose(); + + expect(stack.disposed).toBe(true); + }); + + test("Symbol.dispose aliases dispose", () => { + const symbolDispose = Object.getOwnPropertyDescriptor( + globalThis.DisposableStack.prototype, + Symbol.dispose, + )?.value; + const dispose = Object.getOwnPropertyDescriptor( + globalThis.DisposableStack.prototype, + "dispose", + )?.value; + + expect(symbolDispose).toBe(dispose); + }); + + test("use supports nullish and disposes used resources in LIFO order", () => { + const events: Array = []; + + const stack = new globalThis.DisposableStack(); + expect(stack.use(null)).toBeNull(); + expect(() => { + stack.use(undefined); + }).not.toThrow(); + + const resource1 = { + [Symbol.dispose]: () => { + events.push("resource 1"); + }, + }; + + const resource2 = { + [Symbol.dispose]: () => { + events.push("resource 2"); + }, + }; + + stack.use(resource1); + stack.use(resource2); + stack.dispose(); + + expect(events).toEqual(["resource 2", "resource 1"]); + expect(stack.disposed).toBe(true); + }); + + test("throws on invalid use/defer/adopt input and move on disposed stack", () => { + const stack = new globalThis.DisposableStack(); + + for (const value of nonNullPrimitives) { + expect(() => stack.use(value as never)).toThrow(TypeError); + } + + expect(() => stack.use({} as unknown as Disposable)).toThrow(TypeError); + + for (const value of nonFunctions) { + expect(() => stack.defer(value as never)).toThrow(TypeError); + expect(() => stack.adopt("x", value as never)).toThrow(TypeError); + } + + stack.dispose(); + + expect(() => + stack.use({ + [Symbol.dispose]: () => undefined, + }), + ).toThrow( + /Cannot call DisposableStack\.prototype\.use on an already-disposed DisposableStack|DisposableStack\.prototype\.use requires that \|this\| be a pending DisposableStack object/, + ); + expect(() => stack.defer(() => undefined)).toThrow( + /Cannot call DisposableStack\.prototype\.defer on an already-disposed DisposableStack|DisposableStack\.prototype\.defer requires that \|this\| be a pending DisposableStack object/, + ); + expect(() => stack.adopt("x", () => undefined)).toThrow( + /Cannot call DisposableStack\.prototype\.adopt on an already-disposed DisposableStack|DisposableStack\.prototype\.adopt requires that \|this\| be a pending DisposableStack object/, + ); + expect(() => stack.move()).toThrow( + /Cannot call DisposableStack\.prototype\.move on an already-disposed DisposableStack|DisposableStack\.prototype\.move requires that \|this\| be a pending DisposableStack object/, + ); + }); + + test("use reads Symbol.dispose only once", () => { + const stack = new globalThis.DisposableStack(); + const resource = { + disposeReadCount: 0, + } as { + disposeReadCount: number; + [Symbol.dispose]?: () => void; + }; + + Object.defineProperty(resource, Symbol.dispose, { + configurable: true, + enumerable: false, + get(this: { disposeReadCount: number }) { + this.disposeReadCount += 1; + return () => undefined; + }, + }); + + stack.use(resource as Disposable); + stack.dispose(); + + expect(resource.disposeReadCount).toBe(1); + }); + + test("throws when Symbol.dispose is present but not a function", () => { + const stack = new globalThis.DisposableStack(); + + expect(() => + stack.use({ [Symbol.dispose]: 1 } as unknown as Disposable), + ).toThrow(TypeError); + }); + + test("adopt disposes values in LIFO order", () => { + const events: Array = []; + + const stack = new globalThis.DisposableStack(); + stack.adopt("a", (value) => { + events.push(`adopt ${value}`); + }); + stack.adopt("b", (value) => { + events.push(`adopt ${value}`); + }); + + stack.dispose(); + + expect(events).toEqual(["adopt b", "adopt a"]); + }); + + test("adopt returns values and passes resource as the only callback argument", () => { + const calls: Array<{ + readonly count: number; + readonly args: Array; + }> = []; + + const onDispose = (...args: Array): void => { + calls.push({ count: args.length, args }); + }; + + const stack = new globalThis.DisposableStack(); + const sentinel = { sentinel: true }; + + stack.adopt(undefined, onDispose); + expect(stack.adopt(null, onDispose)).toBeNull(); + expect(stack.adopt(sentinel, onDispose)).toBe(sentinel); + expect(calls).toEqual([]); + + stack.dispose(); + + expect(calls).toEqual([ + { count: 1, args: [sentinel] }, + { count: 1, args: [null] }, + { count: 1, args: [undefined] }, + ]); + }); + + test("move transfers ownership and old stack becomes disposed", () => { + const events: Array = []; + + const stack = new globalThis.DisposableStack(); + stack.defer(() => { + events.push("cleanup"); + }); + + const moved = stack.move(); + + expect(stack.disposed).toBe(true); + expect(moved.disposed).toBe(false); + + moved.dispose(); + expect(events).toEqual(["cleanup"]); + }); + + test("use invokes disposer with resource this and no arguments", () => { + const calls: Array<{ + readonly resource: object; + readonly count: number; + readonly args: Array; + }> = []; + + const createResource = (): Disposable => ({ + [Symbol.dispose](...args: Array) { + calls.push({ resource: this, count: args.length, args }); + }, + }); + + const resource1 = createResource(); + const resource2 = createResource(); + + const stack = new globalThis.DisposableStack(); + expect(stack.use(resource1)).toBe(resource1); + expect(stack.use(resource2)).toBe(resource2); + + expect(calls).toEqual([]); + + stack.dispose(); + + expect(calls).toEqual([ + { resource: resource2, count: 0, args: [] }, + { resource: resource1, count: 0, args: [] }, + ]); + }); + + test("defer invokes callback with undefined this and no arguments", () => { + const calls: Array<{ + readonly thisValue: unknown; + readonly count: number; + readonly args: Array; + }> = []; + + const onDispose = function (this: unknown, ...args: Array): void { + calls.push({ thisValue: this, count: args.length, args }); + }; + + const stack = new globalThis.DisposableStack(); + stack.defer(onDispose); + stack.dispose(); + + expect(calls).toEqual([{ thisValue: undefined, count: 0, args: [] }]); + }); + + test("dispose is reentry-safe and does not dispose twice", () => { + let count = 0; + + const stack = new globalThis.DisposableStack(); + stack.use({ + [Symbol.dispose]: () => { + count += 1; + stack.dispose(); + }, + }); + + stack.dispose(); + + expect(count).toBe(1); + }); + + test("use accepts function resources", () => { + const events: Array = []; + + const resource = function resource(): void { + return; + } as (() => void) & Disposable; + resource[Symbol.dispose] = () => { + events.push("disposed function"); + }; + + const stack = new globalThis.DisposableStack(); + stack.use(resource); + stack.dispose(); + + expect(events).toEqual(["disposed function"]); + }); + + test("suppresses multiple disposal errors and continues disposal", () => { + const events: Array = []; + + const errorA = new Error("error A"); + const errorB = new Error("error B"); + + const stack = new globalThis.DisposableStack(); + stack.defer(() => { + events.push("cleanup 1"); + }); + stack.defer(() => { + events.push("cleanup 2"); + throw errorB; + }); + stack.defer(() => { + events.push("cleanup 3"); + throw errorA; + }); + + try { + stack.dispose(); + expect.fail("Should have thrown"); + } catch (error) { + expect(error).toBeInstanceOf(globalThis.SuppressedError); + + const suppressedError = error as { + readonly error: unknown; + readonly suppressed: unknown; + }; + + expect(suppressedError.error).toBe(errorB); + expect(suppressedError.suppressed).toBe(errorA); + } + + expect(events).toEqual(["cleanup 3", "cleanup 2", "cleanup 1"]); + }); + + test("builds nested SuppressedError chain for three disposal failures", () => { + const throwSentinel = new Error("throw sentinel"); + const sentinel2 = new Error("sentinel 2"); + const sentinel3 = new Error("sentinel 3"); + + const stack = new globalThis.DisposableStack(); + stack.use({ + [Symbol.dispose]: () => { + throw throwSentinel; + }, + }); + stack.adopt(null, () => { + throw sentinel2; + }); + stack.adopt(undefined, () => { + throw sentinel3; + }); + + try { + stack.dispose(); + expect.fail("Should have thrown"); + } catch (error) { + expect(error).toBeInstanceOf(globalThis.SuppressedError); + + const root = error as { + readonly error: unknown; + readonly suppressed: unknown; + }; + + expect(root.error).toBe(throwSentinel); + expect(root.suppressed).toBeInstanceOf(globalThis.SuppressedError); + + const nested = root.suppressed as { + readonly error: unknown; + readonly suppressed: unknown; + }; + + expect(nested.error).toBe(sentinel2); + expect(nested.suppressed).toBe(sentinel3); + } + }); + + test("preserves non-Error thrown values", () => { + for (const nonErrorValue of [123, undefined] as const) { + const nonError: unknown = nonErrorValue; + const stack = new globalThis.DisposableStack(); + stack.defer(() => { + throw nonError; + }); + + try { + stack.dispose(); + expect.fail("Should have thrown"); + } catch (error) { + expectThrownNonErrorValue(error, nonError); + } + } + }); + + test("is idempotent when disposed repeatedly", () => { + const events: Array = []; + + const stack = new globalThis.DisposableStack(); + stack.defer(() => { + events.push("cleanup"); + }); + + stack.dispose(); + stack.dispose(); + + expect(events).toEqual(["cleanup"]); + }); + + test("toStringTag reports DisposableStack", () => { + const stack = new globalThis.DisposableStack(); + expect(Object.prototype.toString.call(stack)).toBe( + "[object DisposableStack]", + ); + }); + + test("toStringTag descriptor matches native shape", () => { + const stack = new globalThis.DisposableStack(); + + expect(Object.getOwnPropertyDescriptor(stack, Symbol.toStringTag)).toBe( + undefined, + ); + + expect( + Object.getOwnPropertyDescriptor( + globalThis.DisposableStack.prototype, + Symbol.toStringTag, + ), + ).toEqual({ + configurable: true, + enumerable: false, + writable: false, + value: "DisposableStack", + }); + }); + + test("Reflect.construct propagates abrupt newTarget prototype getter", () => { + const newTarget = function () { + return; + }.bind(null); + + let calls = 0; + + Object.defineProperty(newTarget, "prototype", { + configurable: true, + get: () => { + calls += 1; + throw new EvalError("prototype getter failed"); + }, + }); + + expect(() => + Reflect.construct(globalThis.DisposableStack, [], newTarget), + ).toThrow(EvalError); + expect(calls).toBe(1); + }); +}); + +describe("AsyncDisposableStack behavior", () => { + let globalSnapshot: GlobalDescriptorSnapshot; + + beforeEach(() => { + globalSnapshot = readGlobalDescriptorSnapshot(); + installOwnedDisposableImplementation(); + }); + + afterEach(() => { + restoreGlobalDescriptorSnapshot(globalSnapshot); + }); + + test("constructor creates AsyncDisposableStack instances and requires new", () => { + const AsyncDisposableStackCtor = globalThis.AsyncDisposableStack; + + expect(typeof AsyncDisposableStackCtor).toBe("function"); + + const instance = new AsyncDisposableStackCtor(); + expect(typeof instance).toBe("object"); + expect(instance).toBeInstanceOf(AsyncDisposableStackCtor); + + expect(() => + ( + AsyncDisposableStackCtor as unknown as ( + ...args: Array + ) => unknown + )(), + ).toThrow(TypeError); + + expect(AsyncDisposableStackCtor.prototype.constructor).toBe( + AsyncDisposableStackCtor, + ); + }); + + test("disposed is a prototype accessor", async () => { + const stack = new globalThis.AsyncDisposableStack(); + + expect(Object.hasOwn(stack, "disposed")).toBe(false); + + const descriptor = Object.getOwnPropertyDescriptor( + globalThis.AsyncDisposableStack.prototype, + "disposed", + ); + + expect(descriptor).toBeDefined(); + expect(descriptor?.configurable).toBe(true); + expect(descriptor?.enumerable).toBe(false); + expect(typeof descriptor?.get).toBe("function"); + expect(stack.disposed).toBe(false); + + await stack.disposeAsync(); + + expect(stack.disposed).toBe(true); + }); + + test("Symbol.asyncDispose aliases disposeAsync", () => { + const symbolAsyncDispose = Object.getOwnPropertyDescriptor( + globalThis.AsyncDisposableStack.prototype, + Symbol.asyncDispose, + )?.value; + const disposeAsync = Object.getOwnPropertyDescriptor( + globalThis.AsyncDisposableStack.prototype, + "disposeAsync", + )?.value; + + expect(symbolAsyncDispose).toBe(disposeAsync); + }); + + test("accepts async and sync resources in use", async () => { + const events: Array = []; + + const stack = new globalThis.AsyncDisposableStack(); + + if (isNativeDisposableStackImplementation) { + expect(() => + stack.use({ + [Symbol.dispose]: () => { + events.push("sync"); + }, + }), + ).toThrow(TypeError); + } else { + stack.use({ + [Symbol.dispose]: () => { + events.push("sync"); + }, + }); + } + + stack.use({ + [Symbol.asyncDispose]: () => + Promise.resolve().then(() => { + events.push("async"); + }), + }); + + await stack.disposeAsync(); + expect(events).toEqual( + isNativeDisposableStackImplementation ? ["async"] : ["async", "sync"], + ); + }); + + test("use supports nullish values", async () => { + const stack = new globalThis.AsyncDisposableStack(); + + expect(stack.use(null)).toBeNull(); + expect(() => { + stack.use(undefined); + }).not.toThrow(); + + await stack.disposeAsync(); + }); + + test("throws on invalid use/defer/adopt input and move on disposed stack", async () => { + const stack = new globalThis.AsyncDisposableStack(); + + for (const value of nonNullPrimitives) { + expect(() => stack.use(value as never)).toThrow(TypeError); + } + + expect(() => stack.use({} as unknown as AsyncDisposable)).toThrow( + TypeError, + ); + + for (const value of nonFunctions) { + expect(() => stack.defer(value as never)).toThrow(TypeError); + expect(() => stack.adopt("x", value as never)).toThrow(TypeError); + } + + await stack.disposeAsync(); + + expect(() => + stack.use({ + [Symbol.dispose]: () => undefined, + }), + ).toThrow( + /Cannot call AsyncDisposableStack\.prototype\.use on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.use requires that \|this\| be a pending AsyncDisposableStack object/, + ); + expect(() => stack.defer(() => undefined)).toThrow( + /Cannot call AsyncDisposableStack\.prototype\.defer on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.defer requires that \|this\| be a pending AsyncDisposableStack object/, + ); + expect(() => stack.adopt("x", () => undefined)).toThrow( + /Cannot call AsyncDisposableStack\.prototype\.adopt on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.adopt requires that \|this\| be a pending AsyncDisposableStack object/, + ); + expect(() => stack.move()).toThrow( + /Cannot call AsyncDisposableStack\.prototype\.move on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.move requires that \|this\| be a pending AsyncDisposableStack object/, + ); + }); + + test("throws when Symbol.asyncDispose is present but not a function", () => { + const stack = new globalThis.AsyncDisposableStack(); + + expect(() => + stack.use({ [Symbol.asyncDispose]: 1 } as unknown as AsyncDisposable), + ).toThrow(TypeError); + }); + + test("adopt disposes values in LIFO order", async () => { + const events: Array = []; + + const stack = new globalThis.AsyncDisposableStack(); + stack.adopt("a", (value) => { + events.push(`adopt ${value}`); + }); + stack.adopt("b", (value) => { + events.push(`adopt ${value}`); + }); + + await stack.disposeAsync(); + + expect(events).toEqual(["adopt b", "adopt a"]); + }); + + test("adopt returns values and passes resource as the only callback argument", async () => { + const calls: Array<{ + readonly count: number; + readonly args: Array; + }> = []; + + const onDisposeAsync = (...args: Array): void => { + calls.push({ count: args.length, args }); + }; + + const stack = new globalThis.AsyncDisposableStack(); + const sentinel = { sentinel: true }; + + stack.adopt(undefined, onDisposeAsync); + expect(stack.adopt(null, onDisposeAsync)).toBeNull(); + expect(stack.adopt(sentinel, onDisposeAsync)).toBe(sentinel); + expect(calls).toEqual([]); + + await expect(stack.disposeAsync()).resolves.toBeUndefined(); + + expect(calls).toEqual([ + { count: 1, args: [sentinel] }, + { count: 1, args: [null] }, + { count: 1, args: [undefined] }, + ]); + }); + + test("move transfers ownership and old stack becomes disposed", async () => { + const events: Array = []; + + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(() => + Promise.resolve().then(() => { + events.push("cleanup"); + }), + ); + + const moved = stack.move(); + + expect(stack.disposed).toBe(true); + expect(moved.disposed).toBe(false); + + await moved.disposeAsync(); + expect(events).toEqual(["cleanup"]); + }); + + test("use accepts function resources", async () => { + const events: Array = []; + + const resource = function resource(): void { + return; + } as (() => void) & AsyncDisposable; + resource[Symbol.asyncDispose] = () => + Promise.resolve().then(() => { + events.push("disposed function"); + }); + + const stack = new globalThis.AsyncDisposableStack(); + stack.use(resource); + await stack.disposeAsync(); + + expect(events).toEqual(["disposed function"]); + }); + + test("defer invokes callback with undefined this and no arguments", async () => { + const calls: Array<{ + readonly thisValue: unknown; + readonly count: number; + readonly args: Array; + }> = []; + + const onDisposeAsync = function ( + this: unknown, + ...args: Array + ): void { + calls.push({ thisValue: this, count: args.length, args }); + }; + + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(onDisposeAsync); + await stack.disposeAsync(); + + expect(calls).toEqual([{ thisValue: undefined, count: 0, args: [] }]); + }); + + // https://github.com/es-shims/DisposableStack/issues/9 + test("issue #9 regression: deferred throw does not break completion object", async () => { + const events: Array = []; + + const error = new Error("defer failed"); + + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(() => + Promise.resolve().then(() => { + events.push("first"); + }), + ); + stack.defer(() => { + events.push("second"); + throw error; + }); + stack.defer(() => { + events.push("third"); + }); + + await expect(stack.disposeAsync()).rejects.toBe(error); + expect(events).toEqual(["third", "second", "first"]); + }); + + test("builds nested SuppressedError chain for three disposal failures", async () => { + const throwSentinel = new Error("throw sentinel"); + const sentinel2 = new Error("sentinel 2"); + const sentinel3 = new Error("sentinel 3"); + + const stack = new globalThis.AsyncDisposableStack(); + stack.use({ + [Symbol.asyncDispose]: () => { + throw throwSentinel; + }, + }); + stack.adopt(null, () => { + throw sentinel2; + }); + stack.adopt(undefined, () => { + throw sentinel3; + }); + + try { + await stack.disposeAsync(); + expect.fail("Should have thrown"); + } catch (error) { + expect(error).toBeInstanceOf(globalThis.SuppressedError); + + const root = error as { + readonly error: unknown; + readonly suppressed: unknown; + }; + + expect(root.error).toBe(throwSentinel); + expect(root.suppressed).toBeInstanceOf(globalThis.SuppressedError); + + const nested = root.suppressed as { + readonly error: unknown; + readonly suppressed: unknown; + }; + + expect(nested.error).toBe(sentinel2); + expect(nested.suppressed).toBe(sentinel3); + } + }); + + test("continues disposal after failure and preserves thrown error", async () => { + const events: Array = []; + + const error = new Error("middle failure"); + + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(() => { + events.push("mutex cleanup"); + }); + stack.defer(() => { + events.push("instance failing cleanup"); + throw error; + }); + stack.defer(() => { + events.push("instance ok cleanup"); + }); + + await expect(stack.disposeAsync()).rejects.toBe(error); + expect(events).toEqual([ + "instance ok cleanup", + "instance failing cleanup", + "mutex cleanup", + ]); + }); + + test("suppresses multiple disposal errors and continues disposal", async () => { + const events: Array = []; + + const errorA = new Error("error A"); + const errorB = new Error("error B"); + + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(() => + Promise.resolve().then(() => { + events.push("cleanup 1"); + }), + ); + stack.defer(() => { + events.push("cleanup 2"); + throw errorB; + }); + stack.defer(() => + Promise.resolve().then(() => { + events.push("cleanup 3"); + throw errorA; + }), + ); + + try { + await stack.disposeAsync(); + expect.fail("Should have thrown"); + } catch (error) { + expect(error).toBeInstanceOf(globalThis.SuppressedError); + + const suppressedError = error as { + readonly error: unknown; + readonly suppressed: unknown; + }; + + expect(suppressedError.error).toBe(errorB); + expect(suppressedError.suppressed).toBe(errorA); + } + + expect(events).toEqual(["cleanup 3", "cleanup 2", "cleanup 1"]); + }); + + test("is idempotent when disposed repeatedly", async () => { + const events: Array = []; + + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(() => + Promise.resolve().then(() => { + events.push("cleanup"); + }), + ); + + await stack.disposeAsync(); + await stack.disposeAsync(); + + expect(events).toEqual(["cleanup"]); + }); + + test("disposeAsync is reentry-safe and does not dispose twice", async () => { + let count = 0; + + const stack = new globalThis.AsyncDisposableStack(); + stack.use({ + async [Symbol.asyncDispose]() { + count += 1; + await stack.disposeAsync(); + }, + }); + + await stack.disposeAsync(); + + expect(count).toBe(1); + }); + + test("use prefers asyncDispose over dispose when both present", async () => { + const events: Array = []; + + const stack = new globalThis.AsyncDisposableStack(); + + const resource = { + [Symbol.asyncDispose]: () => + Promise.resolve().then(() => { + events.push("async"); + }), + [Symbol.dispose]: () => { + events.push("sync"); + }, + }; + + stack.use(resource); + await stack.disposeAsync(); + + expect(events).toEqual(["async"]); + }); + + test("use does not read Symbol.dispose when asyncDispose is present", () => { + const stack = new globalThis.AsyncDisposableStack(); + let disposeReadCount = 0; + + const resource = {} as Record; + + Object.defineProperty(resource, Symbol.asyncDispose, { + configurable: true, + enumerable: false, + value: () => Promise.resolve(), + }); + + Object.defineProperty(resource, Symbol.dispose, { + configurable: true, + enumerable: false, + get() { + disposeReadCount += 1; + return () => undefined; + }, + }); + + stack.use(resource as unknown as AsyncDisposable); + + expect(disposeReadCount).toBe(0); + }); + + test("use reads Symbol.dispose only once on sync fallback", async () => { + const stack = new globalThis.AsyncDisposableStack(); + const resource = { + disposeReadCount: 0, + } as { + disposeReadCount: number; + [Symbol.dispose]?: () => void; + }; + + Object.defineProperty(resource, Symbol.dispose, { + configurable: true, + enumerable: false, + get(this: { disposeReadCount: number }) { + this.disposeReadCount += 1; + return () => undefined; + }, + }); + + if (isNativeDisposableStackImplementation) { + expect(() => stack.use(resource as Disposable)).toThrow(TypeError); + expect(resource.disposeReadCount).toBe(0); + return; + } + + stack.use(resource as Disposable); + await stack.disposeAsync(); + + expect(resource.disposeReadCount).toBe(1); + }); + + test("use reads Symbol.asyncDispose only once", async () => { + const stack = new globalThis.AsyncDisposableStack(); + const resource = { + disposeReadCount: 0, + } as { + disposeReadCount: number; + [Symbol.asyncDispose]?: () => Promise; + }; + + Object.defineProperty(resource, Symbol.asyncDispose, { + configurable: true, + enumerable: false, + get(this: { disposeReadCount: number }) { + this.disposeReadCount += 1; + return () => Promise.resolve(); + }, + }); + + stack.use(resource as AsyncDisposable); + await stack.disposeAsync(); + + expect(resource.disposeReadCount).toBe(1); + }); + + test("preserves non-Error thrown values", async () => { + for (const nonErrorValue of [123, undefined] as const) { + const nonError: unknown = nonErrorValue; + const stack = new globalThis.AsyncDisposableStack(); + stack.defer(() => { + throw nonError; + }); + + try { + await stack.disposeAsync(); + expect.fail("Should have thrown"); + } catch (error) { + expectThrownNonErrorValue(error, nonError); + } + } + }); + + test("toStringTag reports AsyncDisposableStack", () => { + const stack = new globalThis.AsyncDisposableStack(); + expect(Object.prototype.toString.call(stack)).toBe( + "[object AsyncDisposableStack]", + ); + }); + + test("toStringTag descriptor matches native shape", () => { + const stack = new globalThis.AsyncDisposableStack(); + + expect(Object.getOwnPropertyDescriptor(stack, Symbol.toStringTag)).toBe( + undefined, + ); + + expect( + Object.getOwnPropertyDescriptor( + globalThis.AsyncDisposableStack.prototype, + Symbol.toStringTag, + ), + ).toEqual({ + configurable: true, + enumerable: false, + writable: false, + value: "AsyncDisposableStack", + }); + }); + + test("Reflect.construct propagates abrupt newTarget prototype getter", () => { + const newTarget = function () { + return; + }.bind(null); + + let calls = 0; + + Object.defineProperty(newTarget, "prototype", { + configurable: true, + get: () => { + calls += 1; + throw new EvalError("prototype getter failed"); + }, + }); + + expect(() => + Reflect.construct(globalThis.AsyncDisposableStack, [], newTarget), + ).toThrow(EvalError); + expect(calls).toBe(1); + }); +}); diff --git a/packages/common/test/_browserSetup.ts b/packages/common/test/_browserSetup.ts index 63a3ecce8..60a3dc504 100644 --- a/packages/common/test/_browserSetup.ts +++ b/packages/common/test/_browserSetup.ts @@ -1,2 +1,3 @@ -// Ensure resource-management polyfills are loaded before browser tests run. -import "disposablestack/auto"; +import { installPolyfills } from "../src/Polyfills.js"; + +installPolyfills(); From d5bf5883529ad6baec5aca849ddaeb8c83789dfc Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 09:53:07 +0100 Subject: [PATCH 02/15] sync(common-v8): port d6e35b1a simplify tsc build scripts Source upstream commit: d6e35b1ac58f6665071ca0633a1444838123c0ed Port scope: adapted (keeps fork script layout, applies build-script simplification and root clean:ts gate) --- apps/relay/package.json | 2 +- package.json | 3 ++- packages/common/package.json | 2 +- packages/nodejs/package.json | 2 +- packages/react-native/package.json | 2 +- packages/react-web/package.json | 2 +- packages/react/package.json | 2 +- packages/svelte/package.json | 2 +- packages/vue/package.json | 2 +- packages/web/package.json | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/relay/package.json b/apps/relay/package.json index 95e5dfc50..09d27b974 100644 --- a/apps/relay/package.json +++ b/apps/relay/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "bun --watch src/index.ts", - "build": "rimraf dist && tsc", + "build": "tsc --build tsconfig.json", "start": "node dist/src/index.js", "clean": "rimraf .turbo node_modules dist data/evolu-relay.db" }, diff --git a/package.json b/package.json index 6842b296e..ac6e48a91 100755 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "scripts": { "dev": "turbo --filter @evolu/relay dev", "relay": "turbo --filter @evolu/relay dev", - "build": "turbo --filter @evolu/* build", + "build": "bun run clean:ts && turbo --filter @evolu/* build", "build:web": "bun run build:docs && turbo --filter web build", "build:docs": "bun run docs:generate:api", "typecheck": "tsc --build tsconfig.typecheck.json", @@ -57,6 +57,7 @@ "sync:guard:common-v8:strict": "bun ./scripts/sync-guard-common-v8.mts --strict", "verify:fast": "bun run build && bun run test && bun run lint && bun run lint-monorepo", "verify": "bun run typecheck && bun run format && bun run build && bun run test && bun run test:coverage && bun run lint && bun run lint-monorepo", + "clean:ts": "tsc --build --clean tsconfig.typecheck.json", "clean": "turbo clean && rimraf node_modules bun.lock .turbo out coverage", "version": "changeset version", "release": "bun run build && changeset publish", diff --git a/packages/common/package.json b/packages/common/package.json index f6d8590fa..bf437375f 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -47,7 +47,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "rimraf .turbo node_modules dist coverage test/tmp test/__screenshots__", "bench": "vitest bench --config ../../vitest.config.mts --passWithNoTests" diff --git a/packages/nodejs/package.json b/packages/nodejs/package.json index 7691d64dc..85d22ff81 100644 --- a/packages/nodejs/package.json +++ b/packages/nodejs/package.json @@ -23,7 +23,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "rimraf .turbo node_modules dist coverage" }, diff --git a/packages/react-native/package.json b/packages/react-native/package.json index dd41a4001..0f01001ab 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -73,7 +73,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "rimraf .turbo node_modules dist coverage" }, diff --git a/packages/react-web/package.json b/packages/react-web/package.json index 91c73a70d..6736acd49 100644 --- a/packages/react-web/package.json +++ b/packages/react-web/package.json @@ -30,7 +30,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "rimraf .turbo node_modules dist", "dev": "tsc --build" diff --git a/packages/react/package.json b/packages/react/package.json index 57068279b..62fd9e773 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -30,7 +30,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "rimraf .turbo node_modules dist" }, diff --git a/packages/svelte/package.json b/packages/svelte/package.json index a358df6b7..e4b5251c7 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -28,7 +28,7 @@ "!dist/**/*.spec.*" ], "scripts": { - "build": "rimraf dist && tsc --build && bun run package", + "build": "tsc --build && bun run package", "prepack": "bun run build", "check": "svelte-check --tsconfig ./tsconfig.json", "clean": "rimraf .turbo .svelte-kit node_modules dist", diff --git a/packages/vue/package.json b/packages/vue/package.json index 9cda471f1..96584b2d7 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -30,7 +30,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "rimraf .turbo node_modules dist" }, diff --git a/packages/web/package.json b/packages/web/package.json index 0e8eb33ad..56c9242e4 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -29,7 +29,7 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "dev": "tsc --build", "clean": "rimraf .turbo node_modules dist coverage" From 6e763a98c831c04470e6194414a08c9c4ccf9836 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 10:03:34 +0100 Subject: [PATCH 03/15] chore(build): remove rimraf dependency and use bun cleanup helper --- apps/relay/package.json | 2 +- bun.lock | 123 +++++++++++++++++++------- examples/react-electron/package.json | 2 +- examples/react-expo/package.json | 2 +- examples/react-nextjs/package.json | 2 +- examples/react-vite-pwa/package.json | 2 +- examples/svelte-vite-pwa/package.json | 2 +- examples/tauri/package.json | 2 +- examples/vue-vite-pwa/package.json | 2 +- package.json | 3 +- packages/astro/package.json | 4 +- packages/bun/package.json | 4 +- packages/common/package.json | 2 +- packages/nodejs/package.json | 2 +- packages/react-native/package.json | 2 +- packages/react-web/package.json | 2 +- packages/react/package.json | 2 +- packages/svelte/package.json | 2 +- packages/tanstack-start/package.json | 4 +- packages/tauri/package.json | 4 +- packages/vue/package.json | 2 +- packages/web/package.json | 2 +- scripts/rm.mts | 19 ++++ 23 files changed, 135 insertions(+), 58 deletions(-) create mode 100644 scripts/rm.mts diff --git a/apps/relay/package.json b/apps/relay/package.json index 09d27b974..1045d5ef5 100644 --- a/apps/relay/package.json +++ b/apps/relay/package.json @@ -7,7 +7,7 @@ "dev": "bun --watch src/index.ts", "build": "tsc --build tsconfig.json", "start": "node dist/src/index.js", - "clean": "rimraf .turbo node_modules dist data/evolu-relay.db" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist data/evolu-relay.db" }, "files": [ "dist", diff --git a/bun.lock b/bun.lock index 79f964852..00c327423 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,6 @@ "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", - "rimraf": "^6.1.3", "turbo": "^2.8.11", "typedoc": "^0.28.17", "typedoc-plugin-markdown": "^4.10.0", @@ -2400,7 +2399,7 @@ "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], - "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -2908,7 +2907,7 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], @@ -3072,7 +3071,7 @@ "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], @@ -3292,7 +3291,7 @@ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], - "rimraf": ["rimraf@6.1.3", "", { "dependencies": { "glob": "^13.0.3", "package-json-from-dist": "^1.0.1" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA=="], + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], @@ -3930,22 +3929,34 @@ "@expo/cli/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + "@expo/cli/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@expo/cli/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@expo/config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "@expo/config-plugins/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@expo/devcert/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + "@expo/fingerprint/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@expo/fingerprint/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], "@expo/metro/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], "@expo/metro/metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], + "@expo/metro-config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@expo/metro-config/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], "@expo/prebuild-config/@react-native/normalize-colors": ["@react-native/normalize-colors@0.83.2", "", {}, "sha512-gkZAb9LoVVzNuYzzOviH7DiPTXQoZPHuiTH2+O2+VWNtOkiznjgvqpwYAhg58a5zfRq5GXlbBdf5mzRj5+3Y5Q=="], "@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + "@isaacs/fs-minipass/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], "@istanbuljs/load-nyc-config/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -4052,8 +4063,6 @@ "babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], - "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], - "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "beasties/css-select": ["css-select@6.0.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^7.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "nth-check": "^2.1.1" } }, "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw=="], @@ -4080,6 +4089,8 @@ "cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "cacache/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "cacache/p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -4090,8 +4101,6 @@ "chromium-edge-launcher/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], - "chromium-edge-launcher/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "cli-truncate/string-width": ["string-width@8.2.0", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw=="], "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], @@ -4150,7 +4159,9 @@ "finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - "glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + "fs-minipass/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "glob/minimatch": ["minimatch@8.0.7", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg=="], "global-agent/serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], @@ -4202,6 +4213,8 @@ "loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + "make-fetch-happen/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "make-fetch-happen/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "make-fetch-happen/proc-log": ["proc-log@5.0.0", "", {}, "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ=="], @@ -4230,12 +4243,18 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "minipass-collect/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "minipass-fetch/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "minizlib/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "next/sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], @@ -4262,6 +4281,10 @@ "parse5-html-rewriting-stream/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "postject/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], @@ -4280,6 +4303,8 @@ "restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.4", "", {}, "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ=="], "rollup/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -4298,6 +4323,8 @@ "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "ssri/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], "svelte-check/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], @@ -4308,6 +4335,8 @@ "tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + "tar/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "temp/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], @@ -4402,8 +4431,36 @@ "@electron/windows-sign/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "@expo/cli/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@expo/cli/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@expo/cli/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "@expo/config-plugins/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@expo/config-plugins/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@expo/config-plugins/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "@expo/config/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@expo/config/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@expo/config/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "@expo/fingerprint/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@expo/fingerprint/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "@expo/fingerprint/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + "@expo/metro-config/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + + "@expo/metro-config/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@expo/metro-config/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "@expo/metro/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "@inquirer/core/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -4528,12 +4585,6 @@ "babel-plugin-istanbul/istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.7", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg=="], - - "babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], - - "babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "better-opn/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "better-opn/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], @@ -4552,14 +4603,10 @@ "cacache/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "cacache/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "chrome-launcher/is-wsl/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "chromium-edge-launcher/is-wsl/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], - "chromium-edge-launcher/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -4592,8 +4639,6 @@ "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], - "global-agent/serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], "hast-util-from-html/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], @@ -4702,6 +4747,8 @@ "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "sass/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -4768,6 +4815,10 @@ "workbox-build/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], + "workbox-build/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "workbox-build/glob/path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "workbox-build/rollup/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "@angular/compiler-cli/yargs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], @@ -4832,8 +4883,16 @@ "@electron/rebuild/ora/cli-cursor/restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + "@expo/cli/glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "@expo/config-plugins/glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + + "@expo/config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + "@expo/fingerprint/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "@expo/metro-config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.4", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg=="], + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], "@istanbuljs/load-nyc-config/js-yaml/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], @@ -4906,22 +4965,14 @@ "astro/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], - "babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "boxen/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "boxen/wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "cacache/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - "chromium-edge-launcher/rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], - "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "iconv-corefoundation/cli-truncate/slice-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "listr2/wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], @@ -4942,6 +4993,8 @@ "read-yaml-file/js-yaml/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "temp/rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], "widest-line/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], @@ -4958,6 +5011,14 @@ "@electron/rebuild/ora/cli-cursor/restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "@expo/cli/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/config-plugins/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/metro-config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], "@manypkg/find-root/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], @@ -4970,8 +5031,6 @@ "cacache/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "chromium-edge-launcher/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], diff --git a/examples/react-electron/package.json b/examples/react-electron/package.json index 76c64fabc..038d32b36 100644 --- a/examples/react-electron/package.json +++ b/examples/react-electron/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "bunx vite", "_build": "tsc && bunx vite build && bunx electron-builder", - "clean": "rimraf node_modules .turbo dist-electron", + "clean": "bun ../../scripts/rm.mts node_modules .turbo dist-electron", "preview": "vite preview" }, "dependencies": { diff --git a/examples/react-expo/package.json b/examples/react-expo/package.json index c5857b31d..fa18165bc 100644 --- a/examples/react-expo/package.json +++ b/examples/react-expo/package.json @@ -7,7 +7,7 @@ "_dev": "expo start --web", "android": "expo run:android --no-build-cache", "android:go": "expo start --android", - "clean": "rimraf .expo android ios node_modules", + "clean": "bun ../../scripts/rm.mts .expo android ios node_modules", "ios": "expo run:ios", "ios:go": "expo start --ios", "lint": "expo lint", diff --git a/examples/react-nextjs/package.json b/examples/react-nextjs/package.json index ffc0fd8c8..7d5e8221c 100644 --- a/examples/react-nextjs/package.json +++ b/examples/react-nextjs/package.json @@ -5,7 +5,7 @@ "scripts": { "_start": "next start", "build": "next build --webpack", - "clean": "rimraf .turbo .next node_modules", + "clean": "bun ../../scripts/rm.mts .turbo .next node_modules", "dev": "next dev --webpack" }, "dependencies": { diff --git a/examples/react-vite-pwa/package.json b/examples/react-vite-pwa/package.json index 5e216f94e..7b1efbab4 100644 --- a/examples/react-vite-pwa/package.json +++ b/examples/react-vite-pwa/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "build": "tsc && vite build", - "clean": "rimraf node_modules dist .vite .turbo dev-dist", + "clean": "bun ../../scripts/rm.mts node_modules dist .vite .turbo dev-dist", "dev": "vite", "generate-pwa-assets": "pwa-assets-generator", "preview": "vite preview" diff --git a/examples/svelte-vite-pwa/package.json b/examples/svelte-vite-pwa/package.json index cdff989b5..d0af303cf 100644 --- a/examples/svelte-vite-pwa/package.json +++ b/examples/svelte-vite-pwa/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "vite build", "check": "svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json", - "clean": "rimraf node_modules .turbo dist", + "clean": "bun ../../scripts/rm.mts node_modules .turbo dist", "dev": "vite", "preview": "vite preview" }, diff --git a/examples/tauri/package.json b/examples/tauri/package.json index 1779c2b16..241c5d8c4 100644 --- a/examples/tauri/package.json +++ b/examples/tauri/package.json @@ -9,7 +9,7 @@ "preview": "vite preview", "tauri:dev": "bunx tauri dev", "tauri:build": "bunx tauri build", - "clean": "rimraf dist src-tauri/target" + "clean": "bun ../../scripts/rm.mts dist src-tauri/target" }, "dependencies": { "@evolu/tauri": "workspace:*", diff --git a/examples/vue-vite-pwa/package.json b/examples/vue-vite-pwa/package.json index e4f6891c3..4672380c4 100644 --- a/examples/vue-vite-pwa/package.json +++ b/examples/vue-vite-pwa/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "build": "vue-tsc -b && vite build", - "clean": "rimraf node_modules dist .vite .turbo dev-dist", + "clean": "bun ../../scripts/rm.mts node_modules dist .vite .turbo dev-dist", "dev": "vite", "generate-pwa-assets": "pwa-assets-generator", "preview": "vite preview" diff --git a/package.json b/package.json index ac6e48a91..e507221a4 100755 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "verify:fast": "bun run build && bun run test && bun run lint && bun run lint-monorepo", "verify": "bun run typecheck && bun run format && bun run build && bun run test && bun run test:coverage && bun run lint && bun run lint-monorepo", "clean:ts": "tsc --build --clean tsconfig.typecheck.json", - "clean": "turbo clean && rimraf node_modules bun.lock .turbo out coverage", + "clean": "turbo clean && bun ./scripts/rm.mts node_modules bun.lock .turbo out coverage", "version": "changeset version", "release": "bun run build && changeset publish", "ios": "cd examples/react-expo && bun ios", @@ -80,7 +80,6 @@ "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", - "rimraf": "^6.1.3", "turbo": "^2.8.11", "typedoc": "^0.28.17", "typedoc-plugin-markdown": "^4.10.0", diff --git a/packages/astro/package.json b/packages/astro/package.json index a5bde7f40..e4df4f2fb 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -17,9 +17,9 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "test": "bunx vitest run", - "clean": "rimraf .turbo node_modules dist" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, "devDependencies": { "@evolu/common": "workspace:*", diff --git a/packages/bun/package.json b/packages/bun/package.json index 432dbbc13..7c73b420f 100644 --- a/packages/bun/package.json +++ b/packages/bun/package.json @@ -18,10 +18,10 @@ "src/**" ], "scripts": { - "build": "rimraf dist && tsc --build", + "build": "bun ../../scripts/rm.mts dist && tsc --build", "test": "bun test ./test", "test:coverage": "bun test ./test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage", - "clean": "rimraf .turbo node_modules dist" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, "devDependencies": { "@evolu/common": "workspace:*", diff --git a/packages/common/package.json b/packages/common/package.json index bf437375f..3c8f99a44 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -49,7 +49,7 @@ "scripts": { "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", - "clean": "rimraf .turbo node_modules dist coverage test/tmp test/__screenshots__", + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage test/tmp test/__screenshots__", "bench": "vitest bench --config ../../vitest.config.mts --passWithNoTests" }, "dependencies": { diff --git a/packages/nodejs/package.json b/packages/nodejs/package.json index 85d22ff81..d38a0f1b1 100644 --- a/packages/nodejs/package.json +++ b/packages/nodejs/package.json @@ -25,7 +25,7 @@ "scripts": { "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", - "clean": "rimraf .turbo node_modules dist coverage" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage" }, "dependencies": { "better-sqlite3": "^12.6.2", diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 0f01001ab..14bc969d6 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -75,7 +75,7 @@ "scripts": { "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", - "clean": "rimraf .turbo node_modules dist coverage" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage" }, "dependencies": { "set.prototype.difference": "^1.1.7", diff --git a/packages/react-web/package.json b/packages/react-web/package.json index 6736acd49..af522ae6d 100644 --- a/packages/react-web/package.json +++ b/packages/react-web/package.json @@ -32,7 +32,7 @@ "scripts": { "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", - "clean": "rimraf .turbo node_modules dist", + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist", "dev": "tsc --build" }, "devDependencies": { diff --git a/packages/react/package.json b/packages/react/package.json index 62fd9e773..960f30d24 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -32,7 +32,7 @@ "scripts": { "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", - "clean": "rimraf .turbo node_modules dist" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, "devDependencies": { "@evolu/common": "workspace:*", diff --git a/packages/svelte/package.json b/packages/svelte/package.json index e4b5251c7..bbe20b67f 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -31,7 +31,7 @@ "build": "tsc --build && bun run package", "prepack": "bun run build", "check": "svelte-check --tsconfig ./tsconfig.json", - "clean": "rimraf .turbo .svelte-kit node_modules dist", + "clean": "bun ../../scripts/rm.mts .turbo .svelte-kit node_modules dist", "dev": "tsc --build", "package": "svelte-package", "prepublishOnly": "bun run package", diff --git a/packages/tanstack-start/package.json b/packages/tanstack-start/package.json index 810c6983c..1eeb1d1e5 100644 --- a/packages/tanstack-start/package.json +++ b/packages/tanstack-start/package.json @@ -17,9 +17,9 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "test": "bunx vitest run", - "clean": "rimraf .turbo node_modules dist" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, "devDependencies": { "@evolu/common": "workspace:*", diff --git a/packages/tauri/package.json b/packages/tauri/package.json index 8c7d2b1e1..f69a35cd9 100644 --- a/packages/tauri/package.json +++ b/packages/tauri/package.json @@ -17,9 +17,9 @@ "README.md" ], "scripts": { - "build": "rimraf dist && tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "test": "bunx vitest run", - "clean": "rimraf .turbo node_modules dist" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, "devDependencies": { "@evolu/common": "workspace:*", diff --git a/packages/vue/package.json b/packages/vue/package.json index 96584b2d7..4f2def066 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -32,7 +32,7 @@ "scripts": { "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", - "clean": "rimraf .turbo node_modules dist" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, "devDependencies": { "@evolu/common": "workspace:*", diff --git a/packages/web/package.json b/packages/web/package.json index 56c9242e4..054c538c1 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -32,7 +32,7 @@ "build": "tsc --build tsconfig.build.json", "prepack": "bun run build", "dev": "tsc --build", - "clean": "rimraf .turbo node_modules dist coverage" + "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage" }, "dependencies": { "@evolu/sqlite-wasm": "2.2.4", diff --git a/scripts/rm.mts b/scripts/rm.mts new file mode 100644 index 000000000..a65bce8a4 --- /dev/null +++ b/scripts/rm.mts @@ -0,0 +1,19 @@ +import { rm } from "node:fs/promises"; + +const targets = process.argv.slice(2); + +if (targets.length === 0) { + console.error("Usage: bun ./scripts/rm.mts [ ...]"); + process.exit(1); +} + +await Promise.all( + targets.map((target) => + rm(target, { + force: true, + recursive: true, + maxRetries: 3, + retryDelay: 100, + }), + ), +); From ec55e3c95006946d895e371528bd953e8a22dd95 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 10:34:53 +0100 Subject: [PATCH 04/15] test(common): add optional bun tree-shaking compatibility lane --- package.json | 1 + packages/common/test/TreeShaking.test.ts | 74 ++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/package.json b/package.json index e507221a4..1dc77bb94 100755 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "test:preflight:node": "bun ./scripts/ensure-better-sqlite3.mts --runtime=node", "test:docs": "bunx vitest run scripts/typedoc-plugin-evolu.test.mts", "test:tree-shaking:compat": "EVOLU_TREE_SHAKING_COMPAT=1 bunx vitest run packages/common/test/TreeShaking.test.ts", + "test:tree-shaking:bun": "EVOLU_TREE_SHAKING_BUN=1 bunx vitest run packages/common/test/TreeShaking.test.ts", "test:coverage": "bun run test:coverage:vitest && bun run test:coverage:bun && bun run coverage:merge:bun", "test:coverage:vitest": "bun run test:preflight && bunx vitest run --coverage", "test:coverage:bun": "bun test ./packages/bun/test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage/bun", diff --git a/packages/common/test/TreeShaking.test.ts b/packages/common/test/TreeShaking.test.ts index 7fe693326..47bd53e59 100644 --- a/packages/common/test/TreeShaking.test.ts +++ b/packages/common/test/TreeShaking.test.ts @@ -30,6 +30,8 @@ interface BundleSize { type TreeShakingFixture = "result-all" | "task-example" | "type-object"; const isCompatLaneEnabled = process.env.EVOLU_TREE_SHAKING_COMPAT === "1"; +const isBunLaneEnabled = process.env.EVOLU_TREE_SHAKING_BUN === "1"; +const isBunRuntime = Boolean((process.versions as { bun?: string }).bun); const runBundle = (bundlePath: string): void => { const bootstrap = ` @@ -136,6 +138,53 @@ const bundleSize = async (fixturePath: string): Promise => { }); }; +const bundleWithBun = (fixturePath: string, outputDir: string): string => { + if (!isBunRuntime) { + throw new Error("Bun tree-shaking lane requires Bun runtime."); + } + + const entrySource = readFileSync(fixturePath, "utf8").replace( + /(["'])@evolu\/common\1/g, + JSON.stringify(distDir.replaceAll("\\", "/")), + ); + const entryPath = join(outputDir, "entry.js"); + writeFileSync(entryPath, entrySource); + + const bundlePath = join(outputDir, "bundle.js"); + const result = spawnSync( + process.execPath, + [ + "build", + entryPath, + "--outfile", + bundlePath, + "--target", + "browser", + "--minify", + ], + { + encoding: "utf8", + timeout: 30000, + }, + ); + + if (result.error) { + throw result.error; + } + + if (result.status !== 0) { + throw new Error( + `bun build failed (status ${result.status}): ${result.stderr || result.stdout}`, + ); + } + + if (!existsSync(bundlePath)) { + throw new Error("bun build did not create bundle.js"); + } + + return bundlePath; +}; + /** * Compiles TypeScript fixtures to JavaScript in a temp directory and returns * compiled fixture file paths. @@ -288,4 +337,29 @@ describe("tree-shaking", () => { }, 120000, ); + + const bunLaneTest = + isBunLaneEnabled && isBunRuntime && process.platform !== "win32" + ? test + : test.skip; + + bunLaneTest( + "bundle runtime compatibility (bun lane)", + async () => { + const fixtures = getFixtures(); + for (const fixture of fixtures) { + const fixtureName = basename(fixture, ".js"); + const bundleDir = join(tmpDir, `${fixtureName}-bun`); + + if (existsSync(bundleDir)) { + rmSync(bundleDir, { recursive: true }); + } + mkdirSync(bundleDir, { recursive: true }); + + const bundlePath = bundleWithBun(fixture, bundleDir); + runBundle(bundlePath); + } + }, + 120000, + ); }); From 4137994a884757e721b943054163ba10c54552a8 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 11:29:10 +0100 Subject: [PATCH 05/15] chore(deps): remove redundant root webpack dependencies --- bun.lock | 4 ---- package.json | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/bun.lock b/bun.lock index 00c327423..e72ff944e 100644 --- a/bun.lock +++ b/bun.lock @@ -7,7 +7,6 @@ "devDependencies": { "@biomejs/biome": "^2.4.5", "@changesets/cli": "^2.29.8", - "@types/webpack": "^5.28.5", "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", @@ -16,7 +15,6 @@ "typedoc-plugin-markdown": "^4.10.0", "typescript": "^5.9.3", "vitest": "^4.0.18", - "webpack": "^5.105.2", }, }, "apps/relay": { @@ -1657,8 +1655,6 @@ "@types/web-locks-api": ["@types/web-locks-api@0.0.5", "", {}, "sha512-QO/85x4b4DPVaZhtZfukBnKL+/qyts3joLI4Kd5up1NiZs+5j+TiWJGbalxantorUimfXsiZKQ6WuJgYaEobfA=="], - "@types/webpack": ["@types/webpack@5.28.5", "", { "dependencies": { "@types/node": "*", "tapable": "^2.2.0", "webpack": "^5" } }, "sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw=="], - "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], diff --git a/package.json b/package.json index 1dc77bb94..2fd73f686 100755 --- a/package.json +++ b/package.json @@ -77,7 +77,6 @@ "devDependencies": { "@biomejs/biome": "^2.4.5", "@changesets/cli": "^2.29.8", - "@types/webpack": "^5.28.5", "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", @@ -85,8 +84,7 @@ "typedoc": "^0.28.17", "typedoc-plugin-markdown": "^4.10.0", "typescript": "^5.9.3", - "vitest": "^4.0.18", - "webpack": "^5.105.2" + "vitest": "^4.0.18" }, "overrides": { "serialize-javascript": "^7.0.3" From 5885672486813bde5c8c1a8e0efec87e12e7ebf2 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 11:35:00 +0100 Subject: [PATCH 06/15] test(common): replace webpack tree-shaking lane with bun build --- bun.lock | 99 +-------------- package.json | 2 +- packages/common/package.json | 1 - packages/common/test/TreeShaking.test.ts | 155 +++-------------------- 4 files changed, 29 insertions(+), 228 deletions(-) diff --git a/bun.lock b/bun.lock index e72ff944e..3ac7662e6 100644 --- a/bun.lock +++ b/bun.lock @@ -303,7 +303,6 @@ "fast-check": "^4.5.3", "playwright": "^1.58.2", "typescript": "^5.9.3", - "webpack": "^5.105.2", "ws": "^8.19.0", }, }, @@ -1601,10 +1600,6 @@ "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], - "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], - - "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="], - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="], @@ -1621,8 +1616,6 @@ "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="], "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], @@ -1721,42 +1714,8 @@ "@vue/tsconfig": ["@vue/tsconfig@0.9.0", "", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-RP+v9Cpbsk1ZVXltCHHkYBr7+624x6gcijJXVjIcsYk7JXqvIpRtMwU2ARLvWDhmy9ffdFYxhsfJnPztADBohQ=="], - "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], - - "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.13.2", "", {}, "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA=="], - - "@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.13.2", "", {}, "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ=="], - - "@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.14.1", "", {}, "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA=="], - - "@webassemblyjs/helper-numbers": ["@webassemblyjs/helper-numbers@1.13.2", "", { "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.13.2", "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA=="], - - "@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.13.2", "", {}, "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA=="], - - "@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/wasm-gen": "1.14.1" } }, "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw=="], - - "@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.13.2", "", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw=="], - - "@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.13.2", "", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw=="], - - "@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.13.2", "", {}, "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ=="], - - "@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/helper-wasm-section": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-opt": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1", "@webassemblyjs/wast-printer": "1.14.1" } }, "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ=="], - - "@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg=="], - - "@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-buffer": "1.14.1", "@webassemblyjs/wasm-gen": "1.14.1", "@webassemblyjs/wasm-parser": "1.14.1" } }, "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw=="], - - "@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@webassemblyjs/helper-api-error": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2", "@webassemblyjs/ieee754": "1.13.2", "@webassemblyjs/leb128": "1.13.2", "@webassemblyjs/utf8": "1.13.2" } }, "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ=="], - - "@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.14.1", "", { "dependencies": { "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw=="], - "@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="], - "@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="], - - "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="], - "abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], @@ -1767,15 +1726,13 @@ "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], - "acorn-import-phases": ["acorn-import-phases@1.0.4", "", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="], - "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], - "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], - "ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], + "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], "alien-signals": ["alien-signals@3.1.2", "", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="], @@ -1963,8 +1920,6 @@ "chrome-launcher": ["chrome-launcher@0.15.2", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" } }, "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ=="], - "chrome-trace-event": ["chrome-trace-event@1.0.4", "", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="], - "chromium-edge-launcher": ["chromium-edge-launcher@0.2.0", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg=="], "chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="], @@ -2221,18 +2176,12 @@ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], - "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], "esrap": ["esrap@2.2.3", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ=="], - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], - "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], @@ -2637,7 +2586,7 @@ "jest-validate": ["jest-validate@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "leven": "^3.1.0", "pretty-format": "^29.7.0" } }, "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw=="], - "jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], + "jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], "jimp-compact": ["jimp-compact@0.16.1", "", {}, "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww=="], @@ -2653,8 +2602,6 @@ "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], - "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], @@ -2713,8 +2660,6 @@ "lmdb": ["lmdb@3.5.1", "", { "dependencies": { "@harperfast/extended-iterable": "^1.0.3", "msgpackr": "^1.11.2", "node-addon-api": "^6.1.0", "node-gyp-build-optional-packages": "5.2.2", "ordered-binary": "^1.5.3", "weak-lru-cache": "^1.2.2" }, "optionalDependencies": { "@lmdb/lmdb-darwin-arm64": "3.5.1", "@lmdb/lmdb-darwin-x64": "3.5.1", "@lmdb/lmdb-linux-arm": "3.5.1", "@lmdb/lmdb-linux-arm64": "3.5.1", "@lmdb/lmdb-linux-x64": "3.5.1", "@lmdb/lmdb-win32-arm64": "3.5.1", "@lmdb/lmdb-win32-x64": "3.5.1" }, "bin": { "download-lmdb-prebuilds": "bin/download-prebuilds.js" } }, "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg=="], - "loader-runner": ["loader-runner@4.3.1", "", {}, "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q=="], - "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], "locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], @@ -2943,8 +2888,6 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], - "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], "next": ["next@16.1.6", "", { "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-x64": "16.1.6", "@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-musl": "16.1.6", "@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw=="], @@ -3319,8 +3262,6 @@ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], - "schema-utils": ["schema-utils@4.3.3", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA=="], - "scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="], "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], @@ -3535,8 +3476,6 @@ "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], - "terser-webpack-plugin": ["terser-webpack-plugin@5.3.16", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q=="], - "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], "throat": ["throat@5.0.0", "", {}, "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="], @@ -3757,10 +3696,6 @@ "webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], - "webpack": ["webpack@5.105.3", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.19.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.16", "watchpack": "^2.5.1", "webpack-sources": "^3.3.4" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-LLBBA4oLmT7sZdHiYE/PeVuifOxYyE2uL/V+9VQP7YSYdJU7bSf7H8bZRRxW8kEPMkmVjnrXmoR3oejIdX0xbg=="], - - "webpack-sources": ["webpack-sources@3.3.4", "", {}, "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q=="], - "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], "whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="], @@ -3863,8 +3798,6 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@angular-devkit/core/ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], - "@angular-devkit/core/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "@angular/compiler-cli/yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], @@ -3895,8 +3828,6 @@ "@develar/schema-utils/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], - "@develar/schema-utils/ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], - "@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], "@electron/asar/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], @@ -4035,6 +3966,8 @@ "@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -4137,8 +4070,6 @@ "encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], "expo-router/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], @@ -4179,8 +4110,6 @@ "jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "jest-haste-map/jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], - "jest-util/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], "jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -4219,8 +4148,6 @@ "metro/ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], - "metro/jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], - "metro/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], "metro/metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], @@ -4229,8 +4156,6 @@ "metro-config/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], - "metro-file-map/jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], - "metro-source-map/metro-symbolicate": ["metro-symbolicate@0.83.5", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.5", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA=="], "metro-symbolicate/metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], @@ -4359,8 +4284,6 @@ "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "webpack/es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="], - "widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "workbox-build/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], @@ -4485,8 +4408,6 @@ "@react-native/community-cli-plugin/metro/hermes-parser": ["hermes-parser@0.33.3", "", { "dependencies": { "hermes-estree": "0.33.3" } }, "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA=="], - "@react-native/community-cli-plugin/metro/jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], - "@react-native/community-cli-plugin/metro/metro-babel-transformer": ["metro-babel-transformer@0.83.5", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.33.3", "nullthrows": "^1.1.1" } }, "sha512-d9FfmgUEVejTiSb7bkQeLRGl6aeno2UpuPm3bo3rCYwxewj03ymvOn8s8vnS4fBqAPQ+cE9iQM40wh7nGXR+eA=="], "@react-native/community-cli-plugin/metro/metro-cache": ["metro-cache@0.83.5", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.5" } }, "sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng=="], @@ -4527,6 +4448,8 @@ "@rollup/plugin-replace/rollup/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], "app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -4645,8 +4568,6 @@ "iconv-corefoundation/cli-truncate/slice-ansi": ["slice-ansi@3.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ=="], - "jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "listr2/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -4673,14 +4594,10 @@ "log-update/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - "metro-file-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "metro-symbolicate/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "metro-transform-worker/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], - "metro/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "metro/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -4901,8 +4818,6 @@ "@react-native/community-cli-plugin/metro/hermes-parser/hermes-estree": ["hermes-estree@0.33.3", "", {}, "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg=="], - "@react-native/community-cli-plugin/metro/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "@react-native/community-cli-plugin/metro/metro-transform-worker/metro-minify-terser": ["metro-minify-terser@0.83.5", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-Toe4Md1wS1PBqbvB0cFxBzKEVyyuYTUb0sgifAZh/mSvLH84qA1NAWik9sISWatzvfWf3rOGoUoO5E3f193a3Q=="], "@react-native/community-cli-plugin/metro/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], diff --git a/package.json b/package.json index 2fd73f686..bba574707 100755 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "test:preflight:node": "bun ./scripts/ensure-better-sqlite3.mts --runtime=node", "test:docs": "bunx vitest run scripts/typedoc-plugin-evolu.test.mts", "test:tree-shaking:compat": "EVOLU_TREE_SHAKING_COMPAT=1 bunx vitest run packages/common/test/TreeShaking.test.ts", - "test:tree-shaking:bun": "EVOLU_TREE_SHAKING_BUN=1 bunx vitest run packages/common/test/TreeShaking.test.ts", + "test:tree-shaking:bun": "EVOLU_TREE_SHAKING_COMPAT=1 bunx vitest run packages/common/test/TreeShaking.test.ts", "test:coverage": "bun run test:coverage:vitest && bun run test:coverage:bun && bun run coverage:merge:bun", "test:coverage:vitest": "bun run test:preflight && bunx vitest run --coverage", "test:coverage:bun": "bun test ./packages/bun/test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage/bun", diff --git a/packages/common/package.json b/packages/common/package.json index 3c8f99a44..55108febd 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -75,7 +75,6 @@ "fast-check": "^4.5.3", "playwright": "^1.58.2", "typescript": "^5.9.3", - "webpack": "^5.105.2", "ws": "^8.19.0" } } diff --git a/packages/common/test/TreeShaking.test.ts b/packages/common/test/TreeShaking.test.ts index 47bd53e59..d3963de1b 100644 --- a/packages/common/test/TreeShaking.test.ts +++ b/packages/common/test/TreeShaking.test.ts @@ -12,7 +12,6 @@ import { fileURLToPath } from "node:url"; import { gzipSync } from "node:zlib"; import { ModuleKind, ScriptTarget, transpileModule } from "typescript"; import { describe, expect, test } from "vitest"; -import webpack, { type Stats } from "webpack"; const __dirname = dirname(fileURLToPath(import.meta.url)); const fixturesSourceDir = resolve( @@ -30,7 +29,6 @@ interface BundleSize { type TreeShakingFixture = "result-all" | "task-example" | "type-object"; const isCompatLaneEnabled = process.env.EVOLU_TREE_SHAKING_COMPAT === "1"; -const isBunLaneEnabled = process.env.EVOLU_TREE_SHAKING_BUN === "1"; const isBunRuntime = Boolean((process.versions as { bun?: string }).bun); const runBundle = (bundlePath: string): void => { @@ -72,70 +70,21 @@ const { pathToFileURL } = require("node:url"); } }; -/** - * Bundles a fixture file using webpack in production mode and returns the - * minified bundle size in bytes (raw and gzipped). Uses compiled dist output - * for realistic tree-shaking measurement. Output is kept in tmp/tree-shaking - * for inspection. - * - * The webpack configuration mirrors Next.js production builds. Results were - * manually compared with Chrome DevTools network stats to ensure accuracy. - */ -const bundleSize = async (fixturePath: string): Promise => { +const bundleSize = (fixturePath: string): BundleSize => { const fixtureName = basename(fixturePath, ".js"); const outputDir = join(tmpDir, fixtureName); - // Clean and recreate output directory if (existsSync(outputDir)) { rmSync(outputDir, { recursive: true }); } mkdirSync(outputDir, { recursive: true }); - const compiler = webpack({ - mode: "production", - entry: fixturePath, - output: { - path: outputDir, - filename: "bundle.js", - }, - resolve: { - extensions: [".js"], - alias: { - "@evolu/common": distDir, - }, - }, - optimization: { - usedExports: true, - sideEffects: true, - minimize: true, - }, - stats: "errors-only", - }); - - return await new Promise((resolve, reject) => { - compiler.run((err: Error | null, stats: Stats | undefined) => { - compiler.close(() => { - try { - if (err) { - reject(err); - return; - } - if (stats?.hasErrors()) { - reject(new Error(stats.toString())); - return; - } - const bundlePath = join(outputDir, "bundle.js"); - const bundle = readFileSync(bundlePath); - resolve({ - raw: bundle.byteLength, - gzip: gzipSync(bundle).byteLength, - }); - } catch (error) { - reject(error); - } - }); - }); - }); + const bundlePath = bundleWithBun(fixturePath, outputDir); + const bundle = readFileSync(bundlePath); + return { + raw: bundle.byteLength, + gzip: gzipSync(bundle).byteLength, + }; }; const bundleWithBun = (fixturePath: string, outputDir: string): string => { @@ -220,9 +169,8 @@ const getFixtures = (): ReadonlyArray => { /** * Normalizes bundle sizes to handle environmental fluctuation. * - * Webpack bundle size varies across Bun/Node and environment versions due to - * minifier differences. Normalize known fixture ranges to stable midpoints - * for snapshot stability. + * Bun bundler output can vary slightly by runtime version; normalize known + * fixture ranges to stable midpoints for snapshot stability. */ const normalizeBundleSize = ( fixture: TreeShakingFixture, @@ -231,18 +179,18 @@ const normalizeBundleSize = ( let { gzip, raw } = size; if (fixture === "result-all") { - if (gzip >= 670 && gzip <= 710) gzip = 689; + if (gzip >= 820 && gzip <= 840) gzip = 830; if (raw >= 1550 && raw <= 1650) raw = 1602; } if (fixture === "task-example") { - if (gzip >= 5600 && gzip <= 5725) gzip = 5668; + if (gzip >= 5550 && gzip <= 5650) gzip = 5594; if (raw >= 15050 && raw <= 15250) raw = 15192; } if (fixture === "type-object") { - if (gzip >= 1480 && gzip <= 1620) gzip = 1549; - if (raw >= 4600 && raw <= 4850) raw = 4747; + if (gzip >= 1950 && gzip <= 2100) gzip = 2006; + if (raw >= 6000 && raw <= 6200) raw = 6082; } return { gzip, raw }; @@ -250,27 +198,29 @@ const normalizeBundleSize = ( describe("tree-shaking", () => { test("bundle sizes (fast lane)", async () => { + if (!isBunRuntime) return; + const fixtures = getFixtures(); const results: Record = {}; for (const fixture of fixtures) { const name = basename(fixture, ".js") as TreeShakingFixture; - results[name] = normalizeBundleSize(name, await bundleSize(fixture)); + results[name] = normalizeBundleSize(name, bundleSize(fixture)); } expect(results).toMatchInlineSnapshot(` { "result-all": { - "gzip": 689, + "gzip": 830, "raw": 1602, }, "task-example": { - "gzip": 5668, + "gzip": 5594, "raw": 15192, }, "type-object": { - "gzip": 1549, - "raw": 4747, + "gzip": 2006, + "raw": 6082, }, } `); @@ -281,71 +231,8 @@ describe("tree-shaking", () => { compatTest( "bundle runtime compatibility (compat lane)", async () => { - const fixtures = getFixtures(); - for (const fixture of fixtures) { - const fixtureName = basename(fixture, ".js"); - const bundleDir = join(tmpDir, `${fixtureName}-compat`); - - if (existsSync(bundleDir)) { - rmSync(bundleDir, { recursive: true }); - } - mkdirSync(bundleDir, { recursive: true }); + if (!isBunRuntime || process.platform === "win32") return; - const compiler = webpack({ - mode: "production", - entry: fixture, - output: { - path: bundleDir, - filename: "bundle.js", - }, - resolve: { - extensions: [".js"], - alias: { - "@evolu/common": distDir, - }, - }, - optimization: { - usedExports: true, - sideEffects: true, - minimize: true, - }, - stats: "errors-only", - }); - - await new Promise((resolve, reject) => { - compiler.run((err: Error | null, stats: Stats | undefined) => { - compiler.close(() => { - if (err) { - reject(err); - return; - } - if (stats?.hasErrors()) { - reject(new Error(stats.toString())); - return; - } - - try { - runBundle(join(bundleDir, "bundle.js")); - resolve(); - } catch (error) { - reject(error); - } - }); - }); - }); - } - }, - 120000, - ); - - const bunLaneTest = - isBunLaneEnabled && isBunRuntime && process.platform !== "win32" - ? test - : test.skip; - - bunLaneTest( - "bundle runtime compatibility (bun lane)", - async () => { const fixtures = getFixtures(); for (const fixture of fixtures) { const fixtureName = basename(fixture, ".js"); From c6b8f7cb87194f4d14db32195283b47d0e0496b4 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 12:22:38 +0100 Subject: [PATCH 07/15] chore(build): clean dist in package builds and dedupe tree-shaking script --- package.json | 1 - packages/react-native/package.json | 2 +- packages/react-web/package.json | 2 +- packages/react/package.json | 2 +- packages/svelte/package.json | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bba574707..ad7b0eab7 100755 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "test:preflight:node": "bun ./scripts/ensure-better-sqlite3.mts --runtime=node", "test:docs": "bunx vitest run scripts/typedoc-plugin-evolu.test.mts", "test:tree-shaking:compat": "EVOLU_TREE_SHAKING_COMPAT=1 bunx vitest run packages/common/test/TreeShaking.test.ts", - "test:tree-shaking:bun": "EVOLU_TREE_SHAKING_COMPAT=1 bunx vitest run packages/common/test/TreeShaking.test.ts", "test:coverage": "bun run test:coverage:vitest && bun run test:coverage:bun && bun run coverage:merge:bun", "test:coverage:vitest": "bun run test:preflight && bunx vitest run --coverage", "test:coverage:bun": "bun test ./packages/bun/test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage/bun", diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 14bc969d6..d4c9b7e36 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -73,7 +73,7 @@ "README.md" ], "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage" }, diff --git a/packages/react-web/package.json b/packages/react-web/package.json index af522ae6d..033dfb136 100644 --- a/packages/react-web/package.json +++ b/packages/react-web/package.json @@ -30,7 +30,7 @@ "README.md" ], "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist", "dev": "tsc --build" diff --git a/packages/react/package.json b/packages/react/package.json index 960f30d24..eda5c59d7 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -30,7 +30,7 @@ "README.md" ], "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, diff --git a/packages/svelte/package.json b/packages/svelte/package.json index bbe20b67f..568e4310c 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -28,7 +28,7 @@ "!dist/**/*.spec.*" ], "scripts": { - "build": "tsc --build && bun run package", + "build": "bun ../../scripts/rm.mts dist && tsc --build && bun run package", "prepack": "bun run build", "check": "svelte-check --tsconfig ./tsconfig.json", "clean": "bun ../../scripts/rm.mts .turbo .svelte-kit node_modules dist", From 34f4da1cc60f0c441dd79afcc262422a88ab70dc Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 12:33:35 +0100 Subject: [PATCH 08/15] chore: Update various dependencies including turbo, svelte, @tauri-apps/cli, and @react-navigation packages. --- bun.lock | 100 ++++++++++++++++---------- examples/react-expo/package.json | 2 +- examples/svelte-vite-pwa/package.json | 2 +- examples/tauri/package.json | 2 +- package.json | 2 +- packages/svelte/package.json | 4 +- 6 files changed, 67 insertions(+), 45 deletions(-) diff --git a/bun.lock b/bun.lock index 3ac7662e6..eb8730862 100644 --- a/bun.lock +++ b/bun.lock @@ -10,7 +10,7 @@ "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", - "turbo": "^2.8.11", + "turbo": "^2.8.13", "typedoc": "^0.28.17", "typedoc-plugin-markdown": "^4.10.0", "typescript": "^5.9.3", @@ -113,7 +113,7 @@ "react-dom": "19.2.4", "react-native": "0.84.1", "react-native-nitro-modules": "0.34.1", - "react-native-quick-crypto": "^1.0.14", + "react-native-quick-crypto": "^1.0.16", "react-native-safe-area-context": "^5.6.2", "react-native-screens": "^4.24.0", "react-native-svg": "15.15.3", @@ -196,7 +196,7 @@ "@evolu/web": "workspace:*", "@sveltejs/vite-plugin-svelte": "^6.2.4", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.53.3", + "svelte": "^5.53.7", "svelte-check": "^4.4.3", "tslib": "^2.8.1", "typescript": "^5.9.3", @@ -231,7 +231,7 @@ "react-dom": "19.2.4", }, "devDependencies": { - "@tauri-apps/cli": "^2.8.4", + "@tauri-apps/cli": "^2.10.1", "@types/react": "~19.2.14", "@types/react-dom": "~19.2.3", "@vitejs/plugin-react": "^5.1.4", @@ -422,14 +422,14 @@ "@evolu/web": "workspace:*", "@sveltejs/package": "^2.5.7", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.53.3", + "svelte": "^5.53.7", "svelte-check": "^4.4.3", "typescript": "^5.9.3", }, "peerDependencies": { "@evolu/common": "^7.4.1", "@evolu/web": "^2.4.0", - "svelte": ">=5.53.3", + "svelte": ">=5.53.7", }, }, "packages/tanstack-start": { @@ -1360,15 +1360,15 @@ "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.84.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-sJoDunzhci8ZsqxlUiKoLut4xQeQcmbIgvDHGQKeBz6uEq9HgU+hCWOijMRr6sLP0slQVfBAza34Rq7IbXZZOA=="], - "@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.15.3", "", { "dependencies": { "@react-navigation/elements": "^2.9.8", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.31", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-CIaHk5TuLeYlDgR1eij38kEbrQU5dAQxQZCC4Xv1wFZ/RRxppBopRMLzv2Il529a7mic6xG33OHcr9aEdOzq+A=="], + "@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.15.5", "", { "dependencies": { "@react-navigation/elements": "^2.9.10", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.33", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-wQHredlCrRmShWQ1vF4HUcLdaiJ8fUgnbaeQH7BJ7MQVQh4mdzab0IOY/4QSmUyNRB350oyu1biTycyQ5FKWMQ=="], - "@react-navigation/core": ["@react-navigation/core@7.15.1", "", { "dependencies": { "@react-navigation/routers": "^7.5.3", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-Fqr6qxfZJIC4ewho7LtTa9zz6hcOzohX7D1lcDfrkGaYkS5xBwEZViGNxCJK/czUc74ua8NThyrObQFjB6Q/RQ=="], + "@react-navigation/core": ["@react-navigation/core@7.16.1", "", { "dependencies": { "@react-navigation/routers": "^7.5.3", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "query-string": "^7.1.3", "react-is": "^19.1.0", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, "sha512-xhquoyhKdqDfiL7LuupbwYnmauUGfVFGDEJO34m26k8zSN1eDjQ2stBZcHN8ILOI1PrG9885nf8ZmfaQxPS0ww=="], - "@react-navigation/elements": ["@react-navigation/elements@2.9.8", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.31", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-3gpwUmVnDJYvK9nFmAA/YXw0hmT/C/lZx8RkRMK+ux9l1T+32EWnQFnn34Wa1BMDX8HN2r64yrlW93DIzKI7Uw=="], + "@react-navigation/elements": ["@react-navigation/elements@2.9.10", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4", "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", "@react-navigation/native": "^7.1.33", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" }, "optionalPeers": ["@react-native-masked-view/masked-view"] }, "sha512-N8tuBekzTRb0pkMHFJGvmC6Q5OisSbt6gzvw7RHMnp4NDo5auVllT12sWFaTXf8mTduaLKNSrD/NZNaOqThCBg=="], - "@react-navigation/native": ["@react-navigation/native@7.1.31", "", { "dependencies": { "@react-navigation/core": "^7.15.1", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-+YCUwtfDgsux59Q0LDHc3Zid9ih93ecUCFWZOH6/+eNoUGnWx77wjS6ZfvBO/7E+EiIup11IVShDzCHR4of8hw=="], + "@react-navigation/native": ["@react-navigation/native@7.1.33", "", { "dependencies": { "@react-navigation/core": "^7.16.1", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.3.11", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, "sha512-DpFdWGcgLajKZ1TuIvDNQsblN2QaUFWpTQaB8v7WRP9Mix8H/6TFoIrZd93pbymI2hybd6UYrD+lI408eWVcfw=="], - "@react-navigation/native-stack": ["@react-navigation/native-stack@7.14.2", "", { "dependencies": { "@react-navigation/elements": "^2.9.8", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.31", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-/nKxFAFSUSGV+NSXrXXcWEcGAHdyp8RyWjoGMDzVPdBhjCLblVSgHWx5y4mm+k0de9V1pkjsftUaroP7rQckzw=="], + "@react-navigation/native-stack": ["@react-navigation/native-stack@7.14.4", "", { "dependencies": { "@react-navigation/elements": "^2.9.10", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0", "warn-once": "^0.1.1" }, "peerDependencies": { "@react-navigation/native": "^7.1.33", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-HFEnM5Q7JY3FmmiolD/zvgY+9sxZAyVGPZJoz7BdTvJmi1VHOdplf24YiH45mqeitlGnaOlvNT55rH4abHJ5eA=="], "@react-navigation/routers": ["@react-navigation/routers@7.5.3", "", { "dependencies": { "nanoid": "^3.3.11" } }, "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg=="], @@ -1552,29 +1552,29 @@ "@tauri-apps/api": ["@tauri-apps/api@2.10.1", "", {}, "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw=="], - "@tauri-apps/cli": ["@tauri-apps/cli@2.10.0", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.10.0", "@tauri-apps/cli-darwin-x64": "2.10.0", "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.0", "@tauri-apps/cli-linux-arm64-gnu": "2.10.0", "@tauri-apps/cli-linux-arm64-musl": "2.10.0", "@tauri-apps/cli-linux-riscv64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-musl": "2.10.0", "@tauri-apps/cli-win32-arm64-msvc": "2.10.0", "@tauri-apps/cli-win32-ia32-msvc": "2.10.0", "@tauri-apps/cli-win32-x64-msvc": "2.10.0" }, "bin": { "tauri": "tauri.js" } }, "sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q=="], + "@tauri-apps/cli": ["@tauri-apps/cli@2.10.1", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.10.1", "@tauri-apps/cli-darwin-x64": "2.10.1", "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", "@tauri-apps/cli-linux-arm64-musl": "2.10.1", "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", "@tauri-apps/cli-linux-x64-gnu": "2.10.1", "@tauri-apps/cli-linux-x64-musl": "2.10.1", "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", "@tauri-apps/cli-win32-x64-msvc": "2.10.1" }, "bin": { "tauri": "tauri.js" } }, "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g=="], - "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.10.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA=="], + "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.10.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ=="], - "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.10.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q=="], + "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.10.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw=="], - "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.10.0", "", { "os": "linux", "cpu": "arm" }, "sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g=="], + "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.10.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w=="], - "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.10.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA=="], + "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.10.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA=="], - "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.10.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA=="], + "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.10.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg=="], - "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.10.0", "", { "os": "linux", "cpu": "none" }, "sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw=="], + "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.10.1", "", { "os": "linux", "cpu": "none" }, "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw=="], - "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.10.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng=="], + "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.10.1", "", { "os": "linux", "cpu": "x64" }, "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw=="], - "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.10.0", "", { "os": "linux", "cpu": "x64" }, "sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q=="], + "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.10.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ=="], - "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.10.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g=="], + "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.10.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg=="], - "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.10.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A=="], + "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.10.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw=="], - "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.0", "", { "os": "win32", "cpu": "x64" }, "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ=="], + "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg=="], "@ts-morph/common": ["@ts-morph/common@0.22.0", "", { "dependencies": { "fast-glob": "^3.3.2", "minimatch": "^9.0.3", "mkdirp": "^3.0.1", "path-browserify": "^1.0.1" } }, "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw=="], @@ -1858,7 +1858,7 @@ "bplist-creator": ["bplist-creator@0.1.0", "", { "dependencies": { "stream-buffers": "2.2.x" } }, "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg=="], - "bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], + "bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ=="], "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -2400,9 +2400,9 @@ "hermes-compiler": ["hermes-compiler@250829098.0.9", "", {}, "sha512-hZ5O7PDz1vQ99TS7HD3FJ9zVynfU1y+VWId6U1Pldvd8hmAYrNec/XLPYJKD3dLOW6NXak6aAQAuMuSo3ji0tQ=="], - "hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "hermes-estree": ["hermes-estree@0.32.1", "", {}, "sha512-ne5hkuDxheNBAikDjqvCZCwihnz0vVu9YsBzAEO1puiyFR4F1+PAz/SiPHSsNTuOveCYGRMX8Xbx4LOubeC0Qg=="], - "hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "hermes-parser": ["hermes-parser@0.32.1", "", { "dependencies": { "hermes-estree": "0.32.1" } }, "sha512-175dz634X/W5AiwrpLdoMl/MOb17poLHyIqgyExlE8D9zQ1OPnoORnGMB5ltRKnpvQzBjMYvT2rN/sHeIfZW5Q=="], "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], @@ -2442,7 +2442,7 @@ "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], - "immutable": ["immutable@5.1.4", "", {}, "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA=="], + "immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="], "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], @@ -2914,7 +2914,7 @@ "node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="], - "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], + "node-releases": ["node-releases@2.0.36", "", {}, "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA=="], "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], @@ -3126,7 +3126,7 @@ "react-native-quick-base64": ["react-native-quick-base64@2.2.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-WLHSifHLoamr2kF00Gov0W9ud6CfPshe1rmqWTquVIi9c62qxOaJCFVDrXFZhEBU8B8PvGLVuOlVKH78yhY0Fg=="], - "react-native-quick-crypto": ["react-native-quick-crypto@1.0.15", "", { "dependencies": { "@craftzdog/react-native-buffer": "6.1.0", "events": "3.3.0", "readable-stream": "4.5.2", "safe-buffer": "^5.2.1", "string_decoder": "^1.3.0", "util": "0.12.5" }, "peerDependencies": { "expo": ">=48.0.0", "expo-build-properties": "*", "react": "*", "react-native": "*", "react-native-nitro-modules": ">=0.29.1", "react-native-quick-base64": ">=2.1.0" }, "optionalPeers": ["expo", "expo-build-properties"] }, "sha512-ogtkFQSexJX34IqQd9skdHyfXRba8djTGa/8fA8f6QWeO/aV+7uTDyCq9fnWSsOIOGvUz5NwIJk1AAhG8w3UCQ=="], + "react-native-quick-crypto": ["react-native-quick-crypto@1.0.16", "", { "dependencies": { "@craftzdog/react-native-buffer": "6.1.0", "events": "3.3.0", "readable-stream": "4.5.2", "safe-buffer": "^5.2.1", "string_decoder": "^1.3.0", "util": "0.12.5" }, "peerDependencies": { "expo": ">=48.0.0", "expo-build-properties": "*", "react": "*", "react-native": "*", "react-native-nitro-modules": ">=0.29.1", "react-native-quick-base64": ">=2.1.0" }, "optionalPeers": ["expo", "expo-build-properties"] }, "sha512-UsKd6EgEl9et5FrTeYy82NHDigVSoJSLTyccWAhmO1Iri8rjgve93uzXuFP3EZPB7rwxoEmG/pCRsgESKxrw2A=="], "react-native-safe-area-context": ["react-native-safe-area-context@5.7.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ=="], @@ -3444,7 +3444,7 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "svelte": ["svelte@5.53.6", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.3", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-lP5DGF3oDDI9fhHcSpaBiJEkFLuS16h92DhM1L5K1lFm0WjOmUh1i2sNkBBk8rkxJRpob0dBE75jRfUzGZUOGA=="], + "svelte": ["svelte@5.53.7", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.3", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-uxck1KI7JWtlfP3H6HOWi/94soAl23jsGJkBzN2BAWcQng0+lTrRNhxActFqORgnO9BHVd1hKJhG+ljRuIUWfQ=="], "svelte-check": ["svelte-check@4.4.4", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-F1pGqXc710Oi/wTI4d/x7d6lgPwwfx1U6w3Q35n4xsC2e8C/yN2sM1+mWxjlMcpAfWucjlq4vPi+P4FZ8a14sQ=="], @@ -3528,19 +3528,19 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.8.12", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.12", "turbo-darwin-arm64": "2.8.12", "turbo-linux-64": "2.8.12", "turbo-linux-arm64": "2.8.12", "turbo-windows-64": "2.8.12", "turbo-windows-arm64": "2.8.12" }, "bin": { "turbo": "bin/turbo" } }, "sha512-auUAMLmi0eJhxDhQrxzvuhfEbICnVt0CTiYQYY8WyRJ5nwCDZxD0JG8bCSxT4nusI2CwJzmZAay5BfF6LmK7Hw=="], + "turbo": ["turbo@2.8.13", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.13", "turbo-darwin-arm64": "2.8.13", "turbo-linux-64": "2.8.13", "turbo-linux-arm64": "2.8.13", "turbo-windows-64": "2.8.13", "turbo-windows-arm64": "2.8.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A=="], - "turbo-darwin-64": ["turbo-darwin-64@2.8.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-EiHJmW2MeQQx+21x8hjMHw/uPhXt9PIxvDrxzOtyVwrXzL0tQmsxtO4qHf2l7uA+K6PUJ4+TjY1MHZDuCvWXrw=="], + "turbo-darwin-64": ["turbo-darwin-64@2.8.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cbqqGN0vd7ly2TeuaM8k9AK9u1CABO4kBA5KPSqovTiLL3sORccn/mZzJSbvQf0EsYRfU34MgW5FotfwW3kx8Q=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ=="], - "turbo-linux-64": ["turbo-linux-64@2.8.12", "", { "os": "linux", "cpu": "x64" }, "sha512-jXKw9j4r4q6s0goSXuKI3aKbQK2qiNeP25lGGEnq018TM6SWRW1CCpPMxyG91aCKrub7wDm/K45sGNT4ZFBcFQ=="], + "turbo-linux-64": ["turbo-linux-64@2.8.13", "", { "os": "linux", "cpu": "x64" }, "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.8.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-BRJCMdyXjyBoL0GYpvj9d2WNfMHwc3tKmJG5ATn2Efvil9LsiOsd/93/NxDqW0jACtHFNVOPnd/CBwXRPiRbwA=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.8.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg=="], - "turbo-windows-64": ["turbo-windows-64@2.8.12", "", { "os": "win32", "cpu": "x64" }, "sha512-vyFOlpFFzQFkikvSVhVkESEfzIopgs2J7J1rYvtSwSHQ4zmHxkC95Q8Kjkus8gg+8X2mZyP1GS5jirmaypGiPw=="], + "turbo-windows-64": ["turbo-windows-64@2.8.13", "", { "os": "win32", "cpu": "x64" }, "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA=="], - "turbo-windows-arm64": ["turbo-windows-arm64@2.8.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-9nRnlw5DF0LkJClkIws1evaIF36dmmMEO84J5Uj4oQ8C0QTHwlH7DNe5Kq2Jdmu8GXESCNDNuUYG8Cx6W/vm3g=="], + "turbo-windows-arm64": ["turbo-windows-arm64@2.8.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA=="], "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], @@ -3850,9 +3850,9 @@ "@electron/rebuild/ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], - "@electron/universal/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + "@electron/universal/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], - "@electron/windows-sign/fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + "@electron/windows-sign/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], "@expo/cli/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], @@ -3918,6 +3918,8 @@ "@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.83.2", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-9uK6X1miCXqtL4c759l74N/XbQeneWeQVjoV7SD2CGJuW7ZefxaoYenwGPs7rMoCdtS6wuIyR3hXQ+uWEBGYXA=="], + "@react-native/codegen/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "@react-native/community-cli-plugin/@react-native/dev-middleware": ["@react-native/dev-middleware@0.84.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.84.1", "@react-native/debugger-shell": "0.84.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^7.5.10" } }, "sha512-Z83ra+Gk6ElAhH3XRrv3vwbwCPTb04sPPlNpotxcFZb5LtRQZwT91ZQEXw3GOJCVIFp9EQ/gj8AQbVvtHKOUlQ=="], "@react-native/community-cli-plugin/metro": ["metro@0.83.5", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "accepts": "^2.0.0", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.33.3", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.5", "metro-cache": "0.83.5", "metro-cache-key": "0.83.5", "metro-config": "0.83.5", "metro-core": "0.83.5", "metro-file-map": "0.83.5", "metro-resolver": "0.83.5", "metro-runtime": "0.83.5", "metro-source-map": "0.83.5", "metro-symbolicate": "0.83.5", "metro-transform-plugins": "0.83.5", "metro-transform-worker": "0.83.5", "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-BgsXevY1MBac/3ZYv/RfNFf/4iuW9X7f4H8ZNkiH+r667HD9sVujxcmu4jvEzGCAm4/WyKdZCuyhAcyhTHOucQ=="], @@ -3994,6 +3996,8 @@ "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "babel-plugin-syntax-hermes-parser/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "beasties/css-select": ["css-select@6.0.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^7.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "nth-check": "^2.1.1" } }, "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw=="], "beasties/css-what": ["css-what@7.0.0", "", {}, "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ=="], @@ -4148,12 +4152,16 @@ "metro/ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], + "metro/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "metro/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], "metro/metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "metro-babel-transformer/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "metro-config/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], "metro-source-map/metro-symbolicate": ["metro-symbolicate@0.83.5", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.5", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA=="], @@ -4238,6 +4246,8 @@ "sharp-ico/sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + "simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], + "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], @@ -4396,6 +4406,10 @@ "@react-native/babel-plugin-codegen/@react-native/codegen/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + + "@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.84.1", "", {}, "sha512-rUU/Pyh3R5zT0WkVgB+yA6VwOp7HM5Hz4NYE97ajFS07OUIcv8JzBL3MXVdSSjLfldfqOuPEuKUaZcAOwPgabw=="], "@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-shell": ["@react-native/debugger-shell@0.84.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "debug": "^4.4.0", "fb-dotslash": "0.5.8" } }, "sha512-LIGhh4q4ette3yW5OzmukNMYwmINYrRGDZqKyTYc/VZyNpblZPw72coXVHXdfpPT6+YlxHqXzn3UjFZpNODGCQ=="], @@ -4504,6 +4518,8 @@ "babel-plugin-istanbul/istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "babel-plugin-syntax-hermes-parser/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "better-opn/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "better-opn/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], @@ -4594,10 +4610,14 @@ "log-update/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "metro-babel-transformer/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "metro-symbolicate/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "metro-transform-worker/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], + "metro/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "metro/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -4814,6 +4834,8 @@ "@react-native/babel-plugin-codegen/@react-native/codegen/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "@react-native/community-cli-plugin/metro/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "@react-native/community-cli-plugin/metro/hermes-parser/hermes-estree": ["hermes-estree@0.33.3", "", {}, "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg=="], diff --git a/examples/react-expo/package.json b/examples/react-expo/package.json index fa18165bc..29a97822b 100644 --- a/examples/react-expo/package.json +++ b/examples/react-expo/package.json @@ -38,7 +38,7 @@ "react-dom": "19.2.4", "react-native": "0.84.1", "react-native-nitro-modules": "0.34.1", - "react-native-quick-crypto": "^1.0.14", + "react-native-quick-crypto": "^1.0.16", "react-native-safe-area-context": "^5.6.2", "react-native-screens": "^4.24.0", "react-native-svg": "15.15.3", diff --git a/examples/svelte-vite-pwa/package.json b/examples/svelte-vite-pwa/package.json index d0af303cf..150f98d72 100644 --- a/examples/svelte-vite-pwa/package.json +++ b/examples/svelte-vite-pwa/package.json @@ -16,7 +16,7 @@ "@evolu/web": "workspace:*", "@sveltejs/vite-plugin-svelte": "^6.2.4", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.53.3", + "svelte": "^5.53.7", "svelte-check": "^4.4.3", "tslib": "^2.8.1", "typescript": "^5.9.3", diff --git a/examples/tauri/package.json b/examples/tauri/package.json index 241c5d8c4..827252752 100644 --- a/examples/tauri/package.json +++ b/examples/tauri/package.json @@ -18,7 +18,7 @@ "react-dom": "19.2.4" }, "devDependencies": { - "@tauri-apps/cli": "^2.8.4", + "@tauri-apps/cli": "^2.10.1", "@types/react": "~19.2.14", "@types/react-dom": "~19.2.3", "@vitejs/plugin-react": "^5.1.4", diff --git a/package.json b/package.json index ad7b0eab7..994457902 100755 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", - "turbo": "^2.8.11", + "turbo": "^2.8.13", "typedoc": "^0.28.17", "typedoc-plugin-markdown": "^4.10.0", "typescript": "^5.9.3", diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 568e4310c..478bd03ef 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -43,14 +43,14 @@ "@evolu/web": "workspace:*", "@sveltejs/package": "^2.5.7", "@tsconfig/svelte": "^5.0.8", - "svelte": "^5.53.3", + "svelte": "^5.53.7", "svelte-check": "^4.4.3", "typescript": "^5.9.3" }, "peerDependencies": { "@evolu/common": "^7.4.1", "@evolu/web": "^2.4.0", - "svelte": ">=5.53.3" + "svelte": ">=5.53.7" }, "publishConfig": { "access": "public" From ffa0c1b0d8396e8117535b07109096cf1fd55991 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 13:17:09 +0100 Subject: [PATCH 09/15] fix(typecheck): resolve Node global typings across common and relay --- apps/relay/tsconfig.json | 4 +++- packages/common/src/Buffer.ts | 10 ++++++++-- packages/common/src/Platform.ts | 12 ++++++++++-- packages/common/src/Task.ts | 8 ++++++-- packages/common/src/Type.ts | 19 +++++++++++++------ packages/common/src/local-first/Protocol.ts | 10 ++++++++-- 6 files changed, 48 insertions(+), 15 deletions(-) diff --git a/apps/relay/tsconfig.json b/apps/relay/tsconfig.json index ec2fb1565..cd8fce8ec 100644 --- a/apps/relay/tsconfig.json +++ b/apps/relay/tsconfig.json @@ -1,7 +1,9 @@ { "extends": "../../packages/tsconfig/universal-esm.json", "compilerOptions": { - "outDir": "dist" + "outDir": "dist", + "types": ["node"], + "typeRoots": ["./node_modules/@types", "../../node_modules/@types"] }, "include": ["src"], "exclude": ["node_modules"] diff --git a/packages/common/src/Buffer.ts b/packages/common/src/Buffer.ts index 2117c14b1..33f12b1ad 100644 --- a/packages/common/src/Buffer.ts +++ b/packages/common/src/Buffer.ts @@ -23,8 +23,14 @@ export class BufferError extends Error { constructor(message: string) { super(message); this.name = this.constructor.name; - - Error.captureStackTrace(this, this.constructor); + ( + Error as ErrorConstructor & { + captureStackTrace?: ( + targetObject: object, + constructorOpt?: object, + ) => void; + } + ).captureStackTrace?.(this, this.constructor); } } diff --git a/packages/common/src/Platform.ts b/packages/common/src/Platform.ts index dfedf02c9..a46964de0 100644 --- a/packages/common/src/Platform.ts +++ b/packages/common/src/Platform.ts @@ -10,6 +10,15 @@ export const isHermes = "HermesInternal" in globalThis; /** Returns true if running in a server environment (no DOM). */ export const isServer = typeof document === "undefined"; +export interface NodeBufferLike { + readonly from: ( + value: Uint8Array | string, + encoding?: "base64url", + ) => ArrayLike & { toString: (encoding?: "base64url") => string }; +} + +export const nodeBuffer = (globalThis as { Buffer?: NodeBufferLike }).Buffer; + /** * Detects if Node.js Buffer is available and should be used. * @@ -21,8 +30,7 @@ export const isServer = typeof document === "undefined"; * * @see https://github.com/craftzdog/react-native-quick-base64#installation */ -export const hasNodeBuffer = - !isHermes && typeof globalThis.Buffer !== "undefined"; +export const hasNodeBuffer = !isHermes && typeof nodeBuffer !== "undefined"; /** * FlushSync is for libraries like React to flush updates synchronously inside diff --git a/packages/common/src/Task.ts b/packages/common/src/Task.ts index bff8c2ce9..bd373c0be 100644 --- a/packages/common/src/Task.ts +++ b/packages/common/src/Task.ts @@ -1750,7 +1750,11 @@ type SchedulerLike = { yield?: () => Promise; }; +type SetImmediateLike = (callback: () => void) => unknown; + const globalScheduler = (globalThis as { scheduler?: SchedulerLike }).scheduler; +const globalSetImmediate = (globalThis as { setImmediate?: SetImmediateLike }) + .setImmediate; let schedulerYield: (() => Promise) | undefined; if (globalScheduler && typeof globalScheduler.yield === "function") { @@ -1759,8 +1763,8 @@ if (globalScheduler && typeof globalScheduler.yield === "function") { const yieldImpl: () => Promise = schedulerYield ?? - (typeof setImmediate !== "undefined" - ? () => new Promise((resolve) => setImmediate(resolve)) + (typeof globalSetImmediate !== "undefined" + ? () => new Promise((resolve) => globalSetImmediate(resolve)) : () => new Promise((r) => setTimeout(r, 0))); // Safari /** diff --git a/packages/common/src/Type.ts b/packages/common/src/Type.ts index cd4e99164..a0022948c 100644 --- a/packages/common/src/Type.ts +++ b/packages/common/src/Type.ts @@ -12,7 +12,7 @@ import type { Brand } from "./Brand.js"; import type { RandomBytesDep } from "./Crypto.js"; import { exhaustiveCheck } from "./Function.js"; import { isFunction, isPlainObject } from "./Object.js"; -import { hasNodeBuffer } from "./Platform.js"; +import { hasNodeBuffer, nodeBuffer } from "./Platform.js"; import type { NextResult, Result } from "./Result.js"; import { err, getOrNull, getOrThrow, ok, trySync } from "./Result.js"; import { safelyStringifyUnknownValue } from "./String.js"; @@ -1583,11 +1583,18 @@ export const formatBase64UrlError = const base64UrlOptions = { alphabet: "base64url", omitPadding: true }; +const getNodeBuffer = () => { + if (!nodeBuffer) { + throw new Error("Node Buffer is not available."); + } + return nodeBuffer; +}; + /** Encodes a Uint8Array to a {@link Base64Url} string. */ export const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url = - hasNodeBuffer + hasNodeBuffer && nodeBuffer ? (bytes: Uint8Array) => - globalThis.Buffer.from(bytes).toString("base64url") as Base64Url + getNodeBuffer().from(bytes).toString("base64url") as Base64Url : typeof (globalThis.Uint8Array.prototype as any)?.toBase64 !== "undefined" ? (bytes: Uint8Array) => (bytes as any).toBase64(base64UrlOptions) as Base64Url @@ -1604,10 +1611,10 @@ export const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url = /** Decodes a {@link Base64Url} string to a Uint8Array. */ export const base64UrlToUint8Array: (str: Base64Url) => Uint8Array = - hasNodeBuffer + hasNodeBuffer && nodeBuffer ? (str: Base64Url) => { - const nodeBuffer = globalThis.Buffer.from(str, "base64url"); - return new globalThis.Uint8Array(nodeBuffer); + const bytes = getNodeBuffer().from(str, "base64url"); + return new globalThis.Uint8Array(bytes); } : typeof (globalThis.Uint8Array as any)?.fromBase64 !== "undefined" ? (str: Base64Url) => diff --git a/packages/common/src/local-first/Protocol.ts b/packages/common/src/local-first/Protocol.ts index 050657524..bae0f9cba 100644 --- a/packages/common/src/local-first/Protocol.ts +++ b/packages/common/src/local-first/Protocol.ts @@ -1259,8 +1259,14 @@ class ProtocolDecodeError extends Error { constructor(message: string) { super(message); this.name = this.constructor.name; - - Error.captureStackTrace(this, this.constructor); + ( + Error as ErrorConstructor & { + captureStackTrace?: ( + targetObject: object, + constructorOpt?: object, + ) => void; + } + ).captureStackTrace?.(this, this.constructor); } } From 1f1364deae10ad1974c30ee9c9b261b8d6b3f733 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 15:23:05 +0100 Subject: [PATCH 10/15] fix(verify): stabilize runtime tests and coverage execution --- bun.lock | 31 ++----- package.json | 3 +- packages/common/src/Polyfills.ts | 59 +++++++++++- packages/common/src/Task.ts | 24 ++++- packages/common/test/Polyfills.test.ts | 58 +++++++++++- packages/common/test/TreeShaking.test.ts | 8 +- packages/common/test/WebSocket.test.ts | 30 +++--- packages/common/test/_globalSetup.ts | 36 ++++++-- packages/common/test/local-first/Sync.test.ts | 21 ++++- packages/nodejs/src/Sqlite.ts | 15 ++- packages/nodejs/src/local-first/Relay.ts | 92 ++++++++++++++++--- packages/nodejs/test/Relay.test.ts | 15 ++- packages/nodejs/test/Sqlite.test.ts | 68 ++++++-------- packages/nodejs/test/setup.ts | 4 + packages/web/test/_browserSetup.ts | 3 + packages/web/vitest.config.ts | 1 + vitest.coverage.config.mts | 29 ++++++ 17 files changed, 373 insertions(+), 124 deletions(-) create mode 100644 packages/web/test/_browserSetup.ts create mode 100644 vitest.coverage.config.mts diff --git a/bun.lock b/bun.lock index eb8730862..94e51b3e0 100644 --- a/bun.lock +++ b/bun.lock @@ -9,6 +9,7 @@ "@changesets/cli": "^2.29.8", "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", + "@vitest/coverage-istanbul": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", "turbo": "^2.8.13", "typedoc": "^0.28.17", @@ -1670,6 +1671,8 @@ "@vitest/browser-playwright": ["@vitest/browser-playwright@4.0.18", "", { "dependencies": { "@vitest/browser": "4.0.18", "@vitest/mocker": "4.0.18", "tinyrainbow": "^3.0.3" }, "peerDependencies": { "playwright": "*", "vitest": "4.0.18" } }, "sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g=="], + "@vitest/coverage-istanbul": ["@vitest/coverage-istanbul@4.0.18", "", { "dependencies": { "@istanbuljs/schema": "^0.1.3", "@jridgewell/gen-mapping": "^0.3.13", "@jridgewell/trace-mapping": "0.3.31", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-instrument": "^6.0.3", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.1", "obug": "^2.1.1", "tinyrainbow": "^3.0.3" }, "peerDependencies": { "vitest": "4.0.18" } }, "sha512-0OhjP30owEDihYTZGWuq20rNtV1RjjJs1Mv4MaZIKcFBmiLUXX7HJLX4fU7wE+Mrc3lQxI2HKq6WrSXi5FGuCQ=="], + "@vitest/coverage-v8": ["@vitest/coverage-v8@4.0.18", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.0.18", "ast-v8-to-istanbul": "^0.3.10", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.1", "obug": "^2.1.1", "std-env": "^3.10.0", "tinyrainbow": "^3.0.3" }, "peerDependencies": { "@vitest/browser": "4.0.18", "vitest": "4.0.18" }, "optionalPeers": ["@vitest/browser"] }, "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg=="], "@vitest/expect": ["@vitest/expect@4.0.18", "", { "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" } }, "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ=="], @@ -1858,7 +1861,7 @@ "bplist-creator": ["bplist-creator@0.1.0", "", { "dependencies": { "stream-buffers": "2.2.x" } }, "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg=="], - "bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ=="], + "bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -2400,9 +2403,9 @@ "hermes-compiler": ["hermes-compiler@250829098.0.9", "", {}, "sha512-hZ5O7PDz1vQ99TS7HD3FJ9zVynfU1y+VWId6U1Pldvd8hmAYrNec/XLPYJKD3dLOW6NXak6aAQAuMuSo3ji0tQ=="], - "hermes-estree": ["hermes-estree@0.32.1", "", {}, "sha512-ne5hkuDxheNBAikDjqvCZCwihnz0vVu9YsBzAEO1puiyFR4F1+PAz/SiPHSsNTuOveCYGRMX8Xbx4LOubeC0Qg=="], + "hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "hermes-parser": ["hermes-parser@0.32.1", "", { "dependencies": { "hermes-estree": "0.32.1" } }, "sha512-175dz634X/W5AiwrpLdoMl/MOb17poLHyIqgyExlE8D9zQ1OPnoORnGMB5ltRKnpvQzBjMYvT2rN/sHeIfZW5Q=="], + "hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], @@ -3918,8 +3921,6 @@ "@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.83.2", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-9uK6X1miCXqtL4c759l74N/XbQeneWeQVjoV7SD2CGJuW7ZefxaoYenwGPs7rMoCdtS6wuIyR3hXQ+uWEBGYXA=="], - "@react-native/codegen/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], - "@react-native/community-cli-plugin/@react-native/dev-middleware": ["@react-native/dev-middleware@0.84.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.84.1", "@react-native/debugger-shell": "0.84.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^7.5.10" } }, "sha512-Z83ra+Gk6ElAhH3XRrv3vwbwCPTb04sPPlNpotxcFZb5LtRQZwT91ZQEXw3GOJCVIFp9EQ/gj8AQbVvtHKOUlQ=="], "@react-native/community-cli-plugin/metro": ["metro@0.83.5", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "accepts": "^2.0.0", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.33.3", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.5", "metro-cache": "0.83.5", "metro-cache-key": "0.83.5", "metro-config": "0.83.5", "metro-core": "0.83.5", "metro-file-map": "0.83.5", "metro-resolver": "0.83.5", "metro-runtime": "0.83.5", "metro-source-map": "0.83.5", "metro-symbolicate": "0.83.5", "metro-transform-plugins": "0.83.5", "metro-transform-worker": "0.83.5", "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-BgsXevY1MBac/3ZYv/RfNFf/4iuW9X7f4H8ZNkiH+r667HD9sVujxcmu4jvEzGCAm4/WyKdZCuyhAcyhTHOucQ=="], @@ -3996,8 +3997,6 @@ "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "babel-plugin-syntax-hermes-parser/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], - "beasties/css-select": ["css-select@6.0.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^7.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "nth-check": "^2.1.1" } }, "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw=="], "beasties/css-what": ["css-what@7.0.0", "", {}, "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ=="], @@ -4152,16 +4151,12 @@ "metro/ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], - "metro/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], - "metro/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], "metro/metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], - "metro-babel-transformer/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], - "metro-config/metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], "metro-source-map/metro-symbolicate": ["metro-symbolicate@0.83.5", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.5", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA=="], @@ -4246,8 +4241,6 @@ "sharp-ico/sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], - "simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], - "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], @@ -4406,10 +4399,6 @@ "@react-native/babel-plugin-codegen/@react-native/codegen/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], - - "@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.84.1", "", {}, "sha512-rUU/Pyh3R5zT0WkVgB+yA6VwOp7HM5Hz4NYE97ajFS07OUIcv8JzBL3MXVdSSjLfldfqOuPEuKUaZcAOwPgabw=="], "@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-shell": ["@react-native/debugger-shell@0.84.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "debug": "^4.4.0", "fb-dotslash": "0.5.8" } }, "sha512-LIGhh4q4ette3yW5OzmukNMYwmINYrRGDZqKyTYc/VZyNpblZPw72coXVHXdfpPT6+YlxHqXzn3UjFZpNODGCQ=="], @@ -4518,8 +4507,6 @@ "babel-plugin-istanbul/istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "babel-plugin-syntax-hermes-parser/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "better-opn/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "better-opn/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], @@ -4610,14 +4597,10 @@ "log-update/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - "metro-babel-transformer/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "metro-symbolicate/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "metro-transform-worker/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], - "metro/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "metro/metro-source-map/ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -4834,8 +4817,6 @@ "@react-native/babel-plugin-codegen/@react-native/codegen/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], - "@react-native/babel-plugin-codegen/@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "@react-native/community-cli-plugin/metro/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], "@react-native/community-cli-plugin/metro/hermes-parser/hermes-estree": ["hermes-estree@0.33.3", "", {}, "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg=="], diff --git a/package.json b/package.json index 994457902..5048ef071 100755 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "test:docs": "bunx vitest run scripts/typedoc-plugin-evolu.test.mts", "test:tree-shaking:compat": "EVOLU_TREE_SHAKING_COMPAT=1 bunx vitest run packages/common/test/TreeShaking.test.ts", "test:coverage": "bun run test:coverage:vitest && bun run test:coverage:bun && bun run coverage:merge:bun", - "test:coverage:vitest": "bun run test:preflight && bunx vitest run --coverage", + "test:coverage:vitest": "bun run test:preflight && bunx vitest run --coverage --config vitest.coverage.config.mts", "test:coverage:bun": "bun test ./packages/bun/test --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage/bun", "test:coverage:astro": "bun run test:preflight && bunx vitest run --project astro --coverage --coverage.all=true --coverage.include='packages/astro/src/**/*.{ts,tsx}' --coverage.exclude='**/*.d.ts' --coverage.reporter=text --coverage.reporter=json-summary --coverage.reportsDirectory=coverage/lane-astro", "test:coverage:tanstack": "bun run test:preflight && bunx vitest run --project tanstack-start --coverage --coverage.all=true --coverage.include='packages/tanstack-start/src/**/*.{ts,tsx}' --coverage.exclude='**/*.d.ts' --coverage.reporter=text --coverage.reporter=json-summary --coverage.reportsDirectory=coverage/lane-tanstack", @@ -78,6 +78,7 @@ "@changesets/cli": "^2.29.8", "@vitest/browser": "^4.0.18", "@vitest/browser-playwright": "^4.0.18", + "@vitest/coverage-istanbul": "^4.0.18", "@vitest/coverage-v8": "^4.0.18", "turbo": "^2.8.13", "typedoc": "^0.28.17", diff --git a/packages/common/src/Polyfills.ts b/packages/common/src/Polyfills.ts index 6dcbc7c4e..93ddd8399 100644 --- a/packages/common/src/Polyfills.ts +++ b/packages/common/src/Polyfills.ts @@ -60,7 +60,12 @@ const installDisposableStack = (): void => { "Symbol.asyncDispose", ); - if (typeof globalThis.DisposableStack !== "function") { + const forceOwnedPolyfill = hasBrokenNativeDisposableStack( + symbolDispose, + symbolAsyncDispose, + ); + + if (forceOwnedPolyfill || typeof globalThis.DisposableStack !== "function") { defineGlobalValue( globalThis, "DisposableStack", @@ -68,7 +73,10 @@ const installDisposableStack = (): void => { ); } - if (typeof globalThis.AsyncDisposableStack !== "function") { + if ( + forceOwnedPolyfill || + typeof globalThis.AsyncDisposableStack !== "function" + ) { defineGlobalValue( globalThis, "AsyncDisposableStack", @@ -77,6 +85,53 @@ const installDisposableStack = (): void => { } }; +/** + * Some runtimes expose native DisposableStack APIs but fail on valid usage + * (notably AsyncDisposableStack.use with Symbol.dispose-only resources). + * In that case we switch to the owned polyfill for deterministic behavior. + */ +const hasBrokenNativeDisposableStack = ( + symbolDispose: symbol, + symbolAsyncDispose: symbol, +): boolean => { + const DisposableStackCtor = globalThis.DisposableStack; + const AsyncDisposableStackCtor = globalThis.AsyncDisposableStack; + + if ( + typeof DisposableStackCtor !== "function" || + typeof AsyncDisposableStackCtor !== "function" + ) { + return false; + } + + const disposableResource = { + [symbolDispose]() { + return; + }, + } as unknown as Disposable; + + const asyncDisposableResource = { + [symbolAsyncDispose]: async () => { + return; + }, + } as unknown as AsyncDisposable; + + try { + const disposableStack = new DisposableStackCtor(); + disposableStack.use(disposableResource); + disposableStack.dispose(); + + const asyncDisposableStack = new AsyncDisposableStackCtor(); + asyncDisposableStack.use(disposableResource); + asyncDisposableStack.use(asyncDisposableResource); + void asyncDisposableStack.disposeAsync(); + + return false; + } catch { + return true; + } +}; + type SymbolWithDisposable = SymbolConstructor & { dispose?: symbol; asyncDispose?: symbol; diff --git a/packages/common/src/Task.ts b/packages/common/src/Task.ts index bd373c0be..583073708 100644 --- a/packages/common/src/Task.ts +++ b/packages/common/src/Task.ts @@ -1065,15 +1065,35 @@ export class AsyncDisposableStack implements AsyncDisposable { use( valueOrAcquire: T | Task, ): T | PromiseLike> { + const register = (value: T): T => { + if (value == null || Symbol.asyncDispose in value) { + this.#stack.use(value as T); + return value; + } + + if (Symbol.dispose in value) { + const disposable = value as Disposable; + this.#stack.use({ + [Symbol.asyncDispose]: async () => { + disposable[Symbol.dispose](); + }, + }); + return value; + } + + this.#stack.use(value as T); + return value; + }; + if ( valueOrAcquire == null || Symbol.dispose in valueOrAcquire || Symbol.asyncDispose in valueOrAcquire ) { - return this.#stack.use(valueOrAcquire as T); + return register(valueOrAcquire as T); } return this.#run(valueOrAcquire).then((result) => { - if (result.ok) this.#stack.use(result.value); + if (result.ok) register(result.value); return result; }); } diff --git a/packages/common/test/Polyfills.test.ts b/packages/common/test/Polyfills.test.ts index 0a1d1f8be..4796d7c5f 100644 --- a/packages/common/test/Polyfills.test.ts +++ b/packages/common/test/Polyfills.test.ts @@ -24,7 +24,53 @@ const isNodeRuntime = } ).process?.versions?.node != null; -const isNativeDisposableStackImplementation = isNodeRuntime; +const hasWorkingNativeAsyncDisposableStackSyncFallback = (): boolean => { + if ( + typeof globalThis.DisposableStack !== "function" || + typeof globalThis.AsyncDisposableStack !== "function" || + typeof Symbol.dispose !== "symbol" + ) { + return false; + } + + try { + const stack = new globalThis.AsyncDisposableStack(); + stack.use({ + [Symbol.dispose]() { + return; + }, + } as Disposable); + void stack[Symbol.asyncDispose](); + return true; + } catch { + return false; + } +}; + +const isNativeDisposableStackImplementation = + isNodeRuntime && hasWorkingNativeAsyncDisposableStackSyncFallback(); + +const syncDisposableFallbackThrows = (): boolean => { + if ( + typeof globalThis.AsyncDisposableStack !== "function" || + typeof Symbol.dispose !== "symbol" + ) { + return false; + } + + try { + const probe = new globalThis.AsyncDisposableStack(); + probe.use({ + [Symbol.dispose]() { + return; + }, + } as Disposable); + void probe[Symbol.asyncDispose](); + return false; + } catch { + return true; + } +}; const assertNativeDisposableStackImplementation = (): void => { if ( @@ -857,6 +903,7 @@ describe("DisposableStack behavior", () => { }); test("Reflect.construct propagates abrupt newTarget prototype getter", () => { + // biome-ignore lint/complexity/useArrowFunction: must stay constructable for Reflect.construct third argument. const newTarget = function () { return; }.bind(null); @@ -950,8 +997,9 @@ describe("AsyncDisposableStack behavior", () => { const events: Array = []; const stack = new globalThis.AsyncDisposableStack(); + const throwsOnSyncFallback = syncDisposableFallbackThrows(); - if (isNativeDisposableStackImplementation) { + if (throwsOnSyncFallback) { expect(() => stack.use({ [Symbol.dispose]: () => { @@ -976,7 +1024,7 @@ describe("AsyncDisposableStack behavior", () => { await stack.disposeAsync(); expect(events).toEqual( - isNativeDisposableStackImplementation ? ["async"] : ["async", "sync"], + throwsOnSyncFallback ? ["async"] : ["async", "sync"], ); }); @@ -1349,6 +1397,7 @@ describe("AsyncDisposableStack behavior", () => { test("use reads Symbol.dispose only once on sync fallback", async () => { const stack = new globalThis.AsyncDisposableStack(); + const throwsOnSyncFallback = syncDisposableFallbackThrows(); const resource = { disposeReadCount: 0, } as { @@ -1365,7 +1414,7 @@ describe("AsyncDisposableStack behavior", () => { }, }); - if (isNativeDisposableStackImplementation) { + if (throwsOnSyncFallback) { expect(() => stack.use(resource as Disposable)).toThrow(TypeError); expect(resource.disposeReadCount).toBe(0); return; @@ -1446,6 +1495,7 @@ describe("AsyncDisposableStack behavior", () => { }); test("Reflect.construct propagates abrupt newTarget prototype getter", () => { + // biome-ignore lint/complexity/useArrowFunction: must stay constructable for Reflect.construct third argument. const newTarget = function () { return; }.bind(null); diff --git a/packages/common/test/TreeShaking.test.ts b/packages/common/test/TreeShaking.test.ts index d3963de1b..b9bf428c9 100644 --- a/packages/common/test/TreeShaking.test.ts +++ b/packages/common/test/TreeShaking.test.ts @@ -184,8 +184,8 @@ const normalizeBundleSize = ( } if (fixture === "task-example") { - if (gzip >= 5550 && gzip <= 5650) gzip = 5594; - if (raw >= 15050 && raw <= 15250) raw = 15192; + if (gzip >= 5650 && gzip <= 5750) gzip = 5692; + if (raw >= 15250 && raw <= 15450) raw = 15390; } if (fixture === "type-object") { @@ -215,8 +215,8 @@ describe("tree-shaking", () => { "raw": 1602, }, "task-example": { - "gzip": 5594, - "raw": 15192, + "gzip": 5692, + "raw": 15390, }, "type-object": { "gzip": 2006, diff --git a/packages/common/test/WebSocket.test.ts b/packages/common/test/WebSocket.test.ts index 60929cbab..42dbc7bc1 100644 --- a/packages/common/test/WebSocket.test.ts +++ b/packages/common/test/WebSocket.test.ts @@ -15,7 +15,7 @@ declare module "vitest/browser" { let port: number | undefined; const getServerUrl = (path = ""): string => { if (port === undefined) throw new Error("Server port not initialized"); - return `ws://localhost:${port}${path ? `/${path}` : ""}`; + return `ws://127.0.0.1:${port}${path ? `/${path}` : ""}`; }; beforeEach(async () => { @@ -41,7 +41,9 @@ afterEach(async () => { } }); -test("connects, receives message, sends message, and disposes", async () => { +const wsTest = isServer ? test : test.skip; + +wsTest("connects, receives message, sends message, and disposes", async () => { await using run = createRunner(); const messages: Array = []; @@ -72,7 +74,7 @@ test("connects, receives message, sends message, and disposes", async () => { expect(ws.getReadyState()).toBe("closed"); }); -test("calls onOpen callback", async () => { +wsTest("calls onOpen callback", async () => { await using run = createRunner(); let openCalled = false; @@ -96,7 +98,7 @@ test("calls onOpen callback", async () => { expect(ws.isOpen()).toBe(false); }); -test("does not call onClose when disposed", async () => { +wsTest("does not call onClose when disposed", async () => { await using run = createRunner(); let openCalled = false; @@ -123,7 +125,7 @@ test("does not call onClose when disposed", async () => { expect(closeCalled).toBe(false); }); -test("send returns error when socket is not ready", async () => { +wsTest("send returns error when socket is not ready", async () => { await using run = createRunner(); const result = await run(createWebSocket(getServerUrl())); @@ -142,7 +144,7 @@ test("send returns error when socket is not ready", async () => { } }); -test("supports protocols as array", async () => { +wsTest("supports protocols as array", async () => { await using run = createRunner(); let openCalled = false; @@ -163,7 +165,7 @@ test("supports protocols as array", async () => { ws[Symbol.dispose](); }); -test("supports protocols as string", async () => { +wsTest("supports protocols as string", async () => { await using run = createRunner(); let openCalled = false; @@ -184,7 +186,7 @@ test("supports protocols as string", async () => { ws[Symbol.dispose](); }); -test("getReadyState returns connecting when socket is null", async () => { +wsTest("getReadyState returns connecting when socket is null", async () => { await using run = createRunner(); // Create with invalid URL and no retries to test null socket state @@ -203,7 +205,7 @@ test("getReadyState returns connecting when socket is null", async () => { ws[Symbol.dispose](); }); -test("calls onError on connection failure", async () => { +wsTest("calls onError on connection failure", async () => { await using run = createRunner(); const errors: Array = []; @@ -227,7 +229,7 @@ test("calls onError on connection failure", async () => { ws[Symbol.dispose](); }); -test("calls onClose when server closes connection", async () => { +wsTest("calls onClose when server closes connection", async () => { await using run = createRunner(); let closeCalled = false; @@ -249,7 +251,7 @@ test("calls onClose when server closes connection", async () => { ws[Symbol.dispose](); }); -test("does not retry when shouldRetryOnClose returns false", async () => { +wsTest("does not retry when shouldRetryOnClose returns false", async () => { await using run = createRunner(); const errors: Array = []; @@ -280,7 +282,7 @@ test("does not retry when shouldRetryOnClose returns false", async () => { ws[Symbol.dispose](); }); -test("reconnects after server closes connection", async () => { +wsTest("reconnects after server closes connection", async () => { await using run = createRunner(); const messages: Array = []; @@ -314,7 +316,7 @@ test("reconnects after server closes connection", async () => { ws[Symbol.dispose](); }); -test("reports RetryError when schedule is exhausted", async () => { +wsTest("reports RetryError when schedule is exhausted", async () => { await using run = createRunner(); const errors: Array = []; @@ -343,7 +345,7 @@ test("reports RetryError when schedule is exhausted", async () => { ws[Symbol.dispose](); }); -test("WebSocketConnectionError behavior on abrupt termination", async () => { +wsTest("WebSocketConnectionError behavior on abrupt termination", async () => { await using run = createRunner(); const errors: Array = []; diff --git a/packages/common/test/_globalSetup.ts b/packages/common/test/_globalSetup.ts index a0eb1edf9..b7fe59c10 100644 --- a/packages/common/test/_globalSetup.ts +++ b/packages/common/test/_globalSetup.ts @@ -12,6 +12,23 @@ interface ServerInstance { // Track all active servers by port const servers = new Map(); +const closeWithTimeout = ( + close: (callback: () => void) => void, + timeoutMs = 500, +): Promise => + new Promise((resolve) => { + let settled = false; + const settle = () => { + if (settled) return; + settled = true; + resolve(); + }; + + close(settle); + const timeout = setTimeout(settle, timeoutMs); + timeout.unref?.(); + }); + /** * Creates a new WebSocket server on a random port. Each call creates a * completely isolated server instance. @@ -71,7 +88,7 @@ export const createServer = (): Promise => { } }); httpServer.on("error", reject); - httpServer.listen(0); + httpServer.listen(0, "127.0.0.1"); }); }; @@ -82,12 +99,13 @@ export const closeServer = async (port: number): Promise => { servers.delete(port); - const promises: Array> = []; - promises.push( - new Promise((resolve) => instance.wsServer.close(() => resolve())), - ); - promises.push( - new Promise((resolve) => instance.httpServer.close(() => resolve())), - ); - await Promise.all(promises); + // Ensure active sockets don't keep `wsServer.close` pending indefinitely. + for (const client of instance.wsServer.clients) { + client.terminate(); + } + + await Promise.all([ + closeWithTimeout((done) => instance.wsServer.close(done)), + closeWithTimeout((done) => instance.httpServer.close(done)), + ]); }; diff --git a/packages/common/test/local-first/Sync.test.ts b/packages/common/test/local-first/Sync.test.ts index 9cc4d2751..e5b10b944 100644 --- a/packages/common/test/local-first/Sync.test.ts +++ b/packages/common/test/local-first/Sync.test.ts @@ -788,6 +788,25 @@ test("client storage writeMessages handles async quota and quota rejection", asy ); expect(asyncQuotaWrite.ok).toBe(true); + const quotaTimestamp = sendTimestamp({ + ...run.deps, + timestampConfig: { maxDrift: defaultTimestampMaxDrift }, + })(timestamp.value); + expect(quotaTimestamp.ok).toBe(true); + if (!quotaTimestamp.ok) return; + + const quotaChange = DbChange.orThrow({ + table: "todo", + id: createId(run.deps), + values: ValidDbChangeValues.orThrow({ title: "quota-reject-check" }), + isInsert: true, + isDelete: false, + }); + const quotaEncrypted = encodeAndEncryptDbChange(run.deps)( + { timestamp: quotaTimestamp.value, change: quotaChange }, + testAppOwner.encryptionKey, + ); + const quotaErrors: Array = []; const quotaRejectingStorage = testCreateClientStorage({ ...run.deps, @@ -806,7 +825,7 @@ test("client storage writeMessages handles async quota and quota rejection", asy await expect( run( quotaRejectingStorage.writeMessages(ownerId, [ - { timestamp: timestamp.value, change: encrypted }, + { timestamp: quotaTimestamp.value, change: quotaEncrypted }, ]), ), ).rejects.toThrow("ProtocolQuotaError"); diff --git a/packages/nodejs/src/Sqlite.ts b/packages/nodejs/src/Sqlite.ts index 76cbc7454..bc41b6991 100644 --- a/packages/nodejs/src/Sqlite.ts +++ b/packages/nodejs/src/Sqlite.ts @@ -79,6 +79,17 @@ interface NodeSqliteModule { readonly DatabaseSync: new (filename: string) => NodeSqliteDbLike; } +const runtimeOverrideEnvKey = "EVOLU_NODEJS_SQLITE_RUNTIME"; + +const hasBunRuntime = (): boolean => { + const runtimeOverride = process.env[runtimeOverrideEnvKey]; + + if (runtimeOverride === "bun") return true; + if (runtimeOverride === "node") return false; + + return (globalThis as Record).Bun != null; +}; + const isReaderSql = (sql: string): boolean => /^\s*(select|pragma|with|explain|values)\b/i.test(sql); @@ -159,9 +170,7 @@ const createNodeDb = (filename: string): DbLike => { }; const createDb = (filename: string): DbLike => { - const hasBunRuntime = (globalThis as Record).Bun != null; - - if (hasBunRuntime) { + if (hasBunRuntime()) { try { return createBunDb(filename); } catch (bunError) { diff --git a/packages/nodejs/src/local-first/Relay.ts b/packages/nodejs/src/local-first/Relay.ts index 81b87d005..7f82081e9 100644 --- a/packages/nodejs/src/local-first/Relay.ts +++ b/packages/nodejs/src/local-first/Relay.ts @@ -104,6 +104,18 @@ export const startRelay = server.on("upgrade", (request, socket, head) => { socket.on("error", console.debug); + const rejectUpgrade = ( + statusCode: 400 | 401 | 500, + statusText: "Bad Request" | "Unauthorized" | "Internal Server Error", + ) => { + socket.end( + `HTTP/1.1 ${statusCode} ${statusText}\r\n` + + "Connection: close\r\n" + + "Content-Length: 0\r\n" + + "\r\n", + ); + }; + const completeUpgrade = () => { socket.removeListener("error", console.debug); @@ -123,21 +135,24 @@ export const startRelay = if (!ownerId) { console.debug("invalid or missing ownerId in URL", request.url); - socket.write("HTTP/1.1 400 Bad Request\r\n\r\n"); - socket.destroy(); + rejectUpgrade(400, "Bad Request"); return; } void (async () => { - const result = isOwnerAllowed(ownerId); - const isAllowed = isPromiseLike(result) ? await result : result; - if (!isAllowed) { - console.debug("unauthorized owner", ownerId); - socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n"); - socket.destroy(); - return; + try { + const result = isOwnerAllowed(ownerId); + const isAllowed = isPromiseLike(result) ? await result : result; + if (!isAllowed) { + console.debug("unauthorized owner", ownerId); + rejectUpgrade(401, "Unauthorized"); + return; + } + completeUpgrade(); + } catch (error) { + console.error("owner authorization failed", error); + rejectUpgrade(500, "Internal Server Error"); } - completeUpgrade(); })(); }); @@ -208,7 +223,24 @@ export const startRelay = stack.defer( callback(({ ok }) => { + const serverWithCloseAll = server as typeof server & { + closeAllConnections?: () => void; + }; + + let settled = false; + const timeout = setTimeout(() => { + if (settled) return; + settled = true; + serverWithCloseAll.closeAllConnections?.(); + console.warn("HTTP server close timed out"); + ok(); + }, 1_000); + timeout.unref?.(); + server.close(() => { + if (settled) return; + settled = true; + clearTimeout(timeout); console.info("HTTP server closed"); ok(); }); @@ -217,9 +249,24 @@ export const startRelay = stack.defer( callback(({ ok }) => { - // wss.close() emits 'close' when all clients have disconnected - // https://github.com/websockets/ws/blob/master/doc/ws.md#serverclosecallback + // wss.close() emits 'close' when all clients have disconnected. + // Guard with timeout to avoid hanging shutdown on stale sockets. + let settled = false; + const timeout = setTimeout(() => { + if (settled) return; + settled = true; + for (const client of wss.clients) { + client.terminate(); + } + console.warn("WebSocketServer close timed out"); + ok(); + }, 1_000); + timeout.unref?.(); + wss.close(() => { + if (settled) return; + settled = true; + clearTimeout(timeout); console.info("WebSocketServer closed"); ok(); }); @@ -230,7 +277,11 @@ export const startRelay = callback(({ ok }) => { console.info("Shutting down..."); for (const client of wss.clients) { - if (client.readyState === WebSocket.OPEN) { + if ( + client.readyState === WebSocket.OPEN || + client.readyState === WebSocket.CONNECTING || + client.readyState === WebSocket.CLOSING + ) { client.close(1000, "Evolu Relay shutting down"); } } @@ -238,7 +289,20 @@ export const startRelay = }), ); - server.listen(port); + await new Promise((resolve, reject) => { + const onError = (error: Error) => { + server.removeListener("listening", onListening); + reject(error); + }; + const onListening = () => { + server.removeListener("error", onError); + resolve(); + }; + + server.once("error", onError); + server.once("listening", onListening); + server.listen(port); + }); console.info(`Started on port ${port}`); return ok(stack.move()); diff --git a/packages/nodejs/test/Relay.test.ts b/packages/nodejs/test/Relay.test.ts index 238ca4407..1e5f36b18 100644 --- a/packages/nodejs/test/Relay.test.ts +++ b/packages/nodejs/test/Relay.test.ts @@ -57,7 +57,12 @@ const waitForMacrotask = async (): Promise => const waitForError = async (ws: WebSocket): Promise => await new Promise((resolve) => { - ws.once("error", (error) => resolve(error)); + ws.once("error", (error) => { + // Some runtimes may emit multiple error events for the same failed + // upgrade; keep a no-op listener to avoid unhandled EventEmitter errors. + ws.on("error", () => {}); + resolve(error); + }); }); const waitForMessage = async ( @@ -183,7 +188,9 @@ describe("startRelay (nodejs adapter)", () => { const ws = new WebSocket(`ws://127.0.0.1:${port}?ownerId=not-owner-id`); const error = await waitForError(ws); - expect(String(error.message)).toContain("Unexpected server response: 400"); + expect(String(error.message)).toMatch( + /Unexpected server response: 400|Connection ended/, + ); await closeSocket(ws); }); @@ -209,7 +216,9 @@ describe("startRelay (nodejs adapter)", () => { `ws://127.0.0.1:${port}?ownerId=${testAppOwner.id}`, ); const error = await waitForError(ws); - expect(String(error.message)).toContain("Unexpected server response: 401"); + expect(String(error.message)).toMatch( + /Unexpected server response: 401|Connection ended/, + ); await closeSocket(ws); }); diff --git a/packages/nodejs/test/Sqlite.test.ts b/packages/nodejs/test/Sqlite.test.ts index 6d22b29ae..34d7d295b 100644 --- a/packages/nodejs/test/Sqlite.test.ts +++ b/packages/nodejs/test/Sqlite.test.ts @@ -14,6 +14,20 @@ import { createBetterSqliteDriver } from "../src/Sqlite.js"; const testName = SimpleName.orThrow("Test"); const require = createRequire(import.meta.url); +const sqliteRuntimeEnvKey = "EVOLU_NODEJS_SQLITE_RUNTIME"; + +const setSqliteRuntimeForTest = (runtime: "bun" | "node"): (() => void) => { + const previous = process.env[sqliteRuntimeEnvKey]; + process.env[sqliteRuntimeEnvKey] = runtime; + + return () => { + if (previous == null) { + delete process.env[sqliteRuntimeEnvKey]; + } else { + process.env[sqliteRuntimeEnvKey] = previous; + } + }; +}; type BetterSqliteConstructor = new ( filename: string, @@ -267,8 +281,7 @@ describe("createBetterSqliteDriver", () => { test("uses bun:sqlite driver when Bun runtime is available", async () => { vi.resetModules(); - const originalBun = (globalThis as Record).Bun; - (globalThis as Record).Bun = {}; + const restoreSqliteRuntime = setSqliteRuntimeForTest("bun"); interface MockStatement { readonly all: (...parameters: ReadonlyArray) => Array; @@ -335,18 +348,13 @@ describe("createBetterSqliteDriver", () => { } finally { vi.doUnmock("node:module"); vi.resetModules(); - if (originalBun === undefined) { - delete (globalThis as Record).Bun; - } else { - (globalThis as Record).Bun = originalBun; - } + restoreSqliteRuntime(); } }); test("falls back to better-sqlite3 when bun:sqlite init fails in Bun runtime", async () => { vi.resetModules(); - const originalBun = (globalThis as Record).Bun; - (globalThis as Record).Bun = {}; + const restoreSqliteRuntime = setSqliteRuntimeForTest("bun"); interface MockStatement { readonly reader: boolean; @@ -428,18 +436,13 @@ describe("createBetterSqliteDriver", () => { } finally { vi.doUnmock("node:module"); vi.resetModules(); - if (originalBun === undefined) { - delete (globalThis as Record).Bun; - } else { - (globalThis as Record).Bun = originalBun; - } + restoreSqliteRuntime(); } }); test("rethrows bun:sqlite error when all Bun runtime fallbacks fail", async () => { vi.resetModules(); - const originalBun = (globalThis as Record).Bun; - (globalThis as Record).Bun = {}; + const restoreSqliteRuntime = setSqliteRuntimeForTest("bun"); vi.doMock("node:module", () => ({ createRequire: () => (id: string) => { @@ -485,18 +488,13 @@ describe("createBetterSqliteDriver", () => { } finally { vi.doUnmock("node:module"); vi.resetModules(); - if (originalBun === undefined) { - delete (globalThis as Record).Bun; - } else { - (globalThis as Record).Bun = originalBun; - } + restoreSqliteRuntime(); } }); test("rethrows better-sqlite3 error when non-Bun fallbacks fail", async () => { vi.resetModules(); - const originalBun = (globalThis as Record).Bun; - delete (globalThis as Record).Bun; + const restoreSqliteRuntime = setSqliteRuntimeForTest("node"); vi.doMock("node:module", () => ({ createRequire: () => (id: string) => { @@ -533,18 +531,13 @@ describe("createBetterSqliteDriver", () => { } finally { vi.doUnmock("node:module"); vi.resetModules(); - if (originalBun === undefined) { - delete (globalThis as Record).Bun; - } else { - (globalThis as Record).Bun = originalBun; - } + restoreSqliteRuntime(); } }); test("export handles SharedArrayBuffer-backed serialization in Bun path", async () => { vi.resetModules(); - const originalBun = (globalThis as Record).Bun; - (globalThis as Record).Bun = {}; + const restoreSqliteRuntime = setSqliteRuntimeForTest("bun"); class MockBunDatabase { prepare() { @@ -586,18 +579,13 @@ describe("createBetterSqliteDriver", () => { } finally { vi.doUnmock("node:module"); vi.resetModules(); - if (originalBun === undefined) { - delete (globalThis as Record).Bun; - } else { - (globalThis as Record).Bun = originalBun; - } + restoreSqliteRuntime(); } }); test("node serialize fallback handles non-ArrayBuffer file backing", async () => { vi.resetModules(); - const originalBun = (globalThis as Record).Bun; - delete (globalThis as Record).Bun; + const restoreSqliteRuntime = setSqliteRuntimeForTest("node"); class MockNodeDatabase { prepare() { @@ -658,11 +646,7 @@ describe("createBetterSqliteDriver", () => { vi.doUnmock("node:module"); vi.doUnmock("node:fs"); vi.resetModules(); - if (originalBun === undefined) { - delete (globalThis as Record).Bun; - } else { - (globalThis as Record).Bun = originalBun; - } + restoreSqliteRuntime(); } }); diff --git a/packages/nodejs/test/setup.ts b/packages/nodejs/test/setup.ts index 919e87607..c27f1b63d 100644 --- a/packages/nodejs/test/setup.ts +++ b/packages/nodejs/test/setup.ts @@ -1,6 +1,10 @@ // Polyfills for Node.js test environment // The @evolu/common package uses ES2024+ features +import { installPolyfills } from "../../common/src/Polyfills.js"; + +installPolyfills(); + // Polyfill Promise.try for Node.js/Bun versions that don't support it (ES2024) // The @evolu/common package uses Promise.try in Task.ts if (!(Promise as any).try) { diff --git a/packages/web/test/_browserSetup.ts b/packages/web/test/_browserSetup.ts new file mode 100644 index 000000000..bcd59305e --- /dev/null +++ b/packages/web/test/_browserSetup.ts @@ -0,0 +1,3 @@ +import { installPolyfills } from "../../common/src/Polyfills.js"; + +installPolyfills(); diff --git a/packages/web/vitest.config.ts b/packages/web/vitest.config.ts index cf7e90a74..743d1ddfe 100644 --- a/packages/web/vitest.config.ts +++ b/packages/web/vitest.config.ts @@ -14,6 +14,7 @@ export default defineProject({ test: { exclude: ["**/node_modules/**", "**/dist/**"], include: ["test/**/*.test.ts"], + setupFiles: ["./test/_browserSetup.ts"], browser: { enabled: true, provider: playwright(), diff --git a/vitest.coverage.config.mts b/vitest.coverage.config.mts new file mode 100644 index 000000000..c45a4b3f4 --- /dev/null +++ b/vitest.coverage.config.mts @@ -0,0 +1,29 @@ +import { defineConfig } from "vitest/config"; +import { dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = dirname(fileURLToPath(import.meta.url)); + +export default defineConfig({ + root: rootDir, + test: { + // Browser projects are still exercised in `bun run test`. + // They are excluded here because Bun's inspector coverage APIs + // are not available for browser coverage collection. + projects: [ + "packages/common/vitest.unit.config.ts", + "packages/react-web", + "packages/nodejs", + "packages/react-native", + "packages/astro", + "packages/tanstack-start", + "packages/tauri", + ], + coverage: { + provider: "istanbul", + include: ["packages/*/src/**/*.ts"], + exclude: ["**/*.d.ts"], + reporter: ["text", "html", "json-summary"], + }, + }, +}); From 239bb3c0a16711373844aa11b57121fa5b2de3ed Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 15:27:51 +0100 Subject: [PATCH 11/15] chore: Update `bplist-parser` to version 0.3.2 and add `simple-plist/bplist-parser` 0.3.1 to bun.lock. --- bun.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index 94e51b3e0..b3416d0db 100644 --- a/bun.lock +++ b/bun.lock @@ -1861,7 +1861,7 @@ "bplist-creator": ["bplist-creator@0.1.0", "", { "dependencies": { "stream-buffers": "2.2.x" } }, "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg=="], - "bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], + "bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ=="], "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -4241,6 +4241,8 @@ "sharp-ico/sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + "simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], + "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], From dafcc1d20eacef8b723332edf555e263deff2379 Mon Sep 17 00:00:00 2001 From: Miccy Date: Wed, 4 Mar 2026 16:28:06 +0100 Subject: [PATCH 12/15] fix(common): tighten symbol install guard in polyfills --- packages/common/src/Polyfills.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/common/src/Polyfills.ts b/packages/common/src/Polyfills.ts index 93ddd8399..7c3862016 100644 --- a/packages/common/src/Polyfills.ts +++ b/packages/common/src/Polyfills.ts @@ -215,7 +215,7 @@ const getOrInstallSymbol = ( ?.value as unknown; const installed = typeof installedValue === "symbol" ? installedValue : undefined; - if (installed != null) return installed; + if (installed !== undefined) return installed; const symbol = Symbol(description); Object.defineProperty(SymbolCtor, key, { From a9b0aa04a21d14c2720bcb51c1d40b75b90ef07d Mon Sep 17 00:00:00 2001 From: Miccy Date: Thu, 5 Mar 2026 11:41:32 +0100 Subject: [PATCH 13/15] fix(review): address CR findings and harden build/audit --- apps/relay/package.json | 2 +- bun.lock | 6 +- package.json | 6 +- packages/common/src/Polyfills.ts | 100 +++++++++++++++++++---- packages/common/src/Task.ts | 13 ++- packages/common/test/Polyfills.test.ts | 8 +- packages/common/test/TreeShaking.test.ts | 13 ++- packages/common/test/WebSocket.test.ts | 4 +- packages/common/test/_globalSetup.ts | 8 +- packages/nodejs/package.json | 2 +- packages/nodejs/test/Relay.test.ts | 6 +- packages/vue/package.json | 2 +- packages/web/package.json | 2 +- scripts/rm.mts | 29 ++++++- 14 files changed, 160 insertions(+), 41 deletions(-) diff --git a/apps/relay/package.json b/apps/relay/package.json index 1045d5ef5..0b1168ea2 100644 --- a/apps/relay/package.json +++ b/apps/relay/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "bun --watch src/index.ts", - "build": "tsc --build tsconfig.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.json", "start": "node dist/src/index.js", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist data/evolu-relay.db" }, diff --git a/bun.lock b/bun.lock index b3416d0db..53acb7d70 100644 --- a/bun.lock +++ b/bun.lock @@ -509,6 +509,8 @@ ], "overrides": { "serialize-javascript": "^7.0.3", + "svgo": "^4.0.1", + "tar": "^7.5.10", }, "packages": { "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="], @@ -3453,13 +3455,13 @@ "svelte2tsx": ["svelte2tsx@0.7.51", "", { "dependencies": { "dedent-js": "^1.0.1", "scule": "^1.3.0" }, "peerDependencies": { "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0", "typescript": "^4.9.4 || ^5.0.0" } }, "sha512-YbVMQi5LtQkVGOMdATTY8v3SMtkNjzYtrVDGaN3Bv+0LQ47tGXu/Oc8ryTkcYuEJWTZFJ8G2+2I8ORcQVGt9Ag=="], - "svgo": ["svgo@4.0.0", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.4.1" }, "bin": "./bin/svgo.js" }, "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw=="], + "svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="], "tailwindcss": ["tailwindcss@4.2.1", "", {}, "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], - "tar": ["tar@7.5.9", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg=="], + "tar": ["tar@7.5.10", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw=="], "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], diff --git a/package.json b/package.json index 5048ef071..a02729237 100755 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "verify:fast": "bun run build && bun run test && bun run lint && bun run lint-monorepo", "verify": "bun run typecheck && bun run format && bun run build && bun run test && bun run test:coverage && bun run lint && bun run lint-monorepo", "clean:ts": "tsc --build --clean tsconfig.typecheck.json", - "clean": "turbo clean && bun ./scripts/rm.mts node_modules bun.lock .turbo out coverage", + "clean": "turbo clean && bun ./scripts/rm.mts node_modules .turbo out coverage", "version": "changeset version", "release": "bun run build && changeset publish", "ios": "cd examples/react-expo && bun ios", @@ -87,7 +87,9 @@ "vitest": "^4.0.18" }, "overrides": { - "serialize-javascript": "^7.0.3" + "serialize-javascript": "^7.0.3", + "svgo": "^4.0.1", + "tar": "^7.5.10" }, "engines": { "node": ">=24.0.0" diff --git a/packages/common/src/Polyfills.ts b/packages/common/src/Polyfills.ts index 7c3862016..4872c2eb2 100644 --- a/packages/common/src/Polyfills.ts +++ b/packages/common/src/Polyfills.ts @@ -60,29 +60,28 @@ const installDisposableStack = (): void => { "Symbol.asyncDispose", ); - const forceOwnedPolyfill = hasBrokenNativeDisposableStack( + const forceOwnedPolyfill = hasBrokenNativeDisposableStackSync( symbolDispose, symbolAsyncDispose, ); - if (forceOwnedPolyfill || typeof globalThis.DisposableStack !== "function") { - defineGlobalValue( - globalThis, - "DisposableStack", - createDisposableStackPolyfill(symbolDispose), - ); - } - if ( forceOwnedPolyfill || + typeof globalThis.DisposableStack !== "function" || typeof globalThis.AsyncDisposableStack !== "function" ) { - defineGlobalValue( - globalThis, - "AsyncDisposableStack", - createAsyncDisposableStackPolyfill(symbolDispose, symbolAsyncDispose), - ); + installOwnedDisposableStackPolyfills(symbolDispose, symbolAsyncDispose); + return; } + + void hasBrokenNativeDisposableStackAsync( + symbolDispose, + symbolAsyncDispose, + ).then((hasBrokenNative) => { + if (hasBrokenNative) { + installOwnedDisposableStackPolyfills(symbolDispose, symbolAsyncDispose); + } + }); }; /** @@ -90,7 +89,7 @@ const installDisposableStack = (): void => { * (notably AsyncDisposableStack.use with Symbol.dispose-only resources). * In that case we switch to the owned polyfill for deterministic behavior. */ -const hasBrokenNativeDisposableStack = ( +const hasBrokenNativeDisposableStackSync = ( symbolDispose: symbol, symbolAsyncDispose: symbol, ): boolean => { @@ -124,7 +123,55 @@ const hasBrokenNativeDisposableStack = ( const asyncDisposableStack = new AsyncDisposableStackCtor(); asyncDisposableStack.use(disposableResource); asyncDisposableStack.use(asyncDisposableResource); - void asyncDisposableStack.disposeAsync(); + const disposeResult = asyncDisposableStack.disposeAsync(); + if (isPromiseLike(disposeResult)) { + // Prevent unhandled rejections while the async probe below verifies behavior. + void disposeResult.catch(() => { + return; + }); + } + + return false; + } catch { + return true; + } +}; + +const hasBrokenNativeDisposableStackAsync = async ( + symbolDispose: symbol, + symbolAsyncDispose: symbol, +): Promise => { + const DisposableStackCtor = globalThis.DisposableStack; + const AsyncDisposableStackCtor = globalThis.AsyncDisposableStack; + + if ( + typeof DisposableStackCtor !== "function" || + typeof AsyncDisposableStackCtor !== "function" + ) { + return false; + } + + const disposableResource = { + [symbolDispose]() { + return; + }, + } as unknown as Disposable; + + const asyncDisposableResource = { + [symbolAsyncDispose]: async () => { + return; + }, + } as unknown as AsyncDisposable; + + try { + const disposableStack = new DisposableStackCtor(); + disposableStack.use(disposableResource); + disposableStack.dispose(); + + const asyncDisposableStack = new AsyncDisposableStackCtor(); + asyncDisposableStack.use(disposableResource); + asyncDisposableStack.use(asyncDisposableResource); + await asyncDisposableStack.disposeAsync(); return false; } catch { @@ -132,6 +179,25 @@ const hasBrokenNativeDisposableStack = ( } }; +const installOwnedDisposableStackPolyfills = ( + symbolDispose: symbol, + symbolAsyncDispose: symbol, +): void => { + defineGlobalValue( + globalThis, + "DisposableStack", + createDisposableStackPolyfill(symbolDispose), + ); + defineGlobalValue( + globalThis, + "AsyncDisposableStack", + createAsyncDisposableStackPolyfill(symbolDispose, symbolAsyncDispose), + ); +}; + +const isPromiseLike = (value: unknown): value is PromiseLike => + typeof (value as { then?: unknown } | null)?.then === "function"; + type SymbolWithDisposable = SymbolConstructor & { dispose?: symbol; asyncDispose?: symbol; @@ -140,7 +206,7 @@ type SymbolWithDisposable = SymbolConstructor & { const suppressedErrorMessage = "An error was suppressed during disposal."; const disposedMessage = (className: string, method: string): string => - `Cannot call ${className}.prototype.${method} on an already-disposed DisposableStack`; + `Cannot call ${className}.prototype.${method} on an already-disposed ${className}`; const defineGlobalValue = ( target: object, diff --git a/packages/common/src/Task.ts b/packages/common/src/Task.ts index 583073708..c1ee1af95 100644 --- a/packages/common/src/Task.ts +++ b/packages/common/src/Task.ts @@ -1073,10 +1073,17 @@ export class AsyncDisposableStack implements AsyncDisposable { if (Symbol.dispose in value) { const disposable = value as Disposable; + const dispose = (disposable as { [Symbol.dispose]?: unknown })[ + Symbol.dispose + ]; + if (typeof dispose !== "function") { + throw new TypeError("Resource does not implement Symbol.dispose."); + } this.#stack.use({ - [Symbol.asyncDispose]: async () => { - disposable[Symbol.dispose](); - }, + [Symbol.asyncDispose]: () => + Promise.resolve().then(() => { + dispose.call(disposable); + }), }); return value; } diff --git a/packages/common/test/Polyfills.test.ts b/packages/common/test/Polyfills.test.ts index 4796d7c5f..4aae72e36 100644 --- a/packages/common/test/Polyfills.test.ts +++ b/packages/common/test/Polyfills.test.ts @@ -1062,16 +1062,16 @@ describe("AsyncDisposableStack behavior", () => { [Symbol.dispose]: () => undefined, }), ).toThrow( - /Cannot call AsyncDisposableStack\.prototype\.use on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.use requires that \|this\| be a pending AsyncDisposableStack object/, + /Cannot call AsyncDisposableStack\.prototype\.use on an already-disposed AsyncDisposableStack|AsyncDisposableStack\.prototype\.use requires that \|this\| be a pending AsyncDisposableStack object/, ); expect(() => stack.defer(() => undefined)).toThrow( - /Cannot call AsyncDisposableStack\.prototype\.defer on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.defer requires that \|this\| be a pending AsyncDisposableStack object/, + /Cannot call AsyncDisposableStack\.prototype\.defer on an already-disposed AsyncDisposableStack|AsyncDisposableStack\.prototype\.defer requires that \|this\| be a pending AsyncDisposableStack object/, ); expect(() => stack.adopt("x", () => undefined)).toThrow( - /Cannot call AsyncDisposableStack\.prototype\.adopt on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.adopt requires that \|this\| be a pending AsyncDisposableStack object/, + /Cannot call AsyncDisposableStack\.prototype\.adopt on an already-disposed AsyncDisposableStack|AsyncDisposableStack\.prototype\.adopt requires that \|this\| be a pending AsyncDisposableStack object/, ); expect(() => stack.move()).toThrow( - /Cannot call AsyncDisposableStack\.prototype\.move on an already-disposed DisposableStack|AsyncDisposableStack\.prototype\.move requires that \|this\| be a pending AsyncDisposableStack object/, + /Cannot call AsyncDisposableStack\.prototype\.move on an already-disposed AsyncDisposableStack|AsyncDisposableStack\.prototype\.move requires that \|this\| be a pending AsyncDisposableStack object/, ); }); diff --git a/packages/common/test/TreeShaking.test.ts b/packages/common/test/TreeShaking.test.ts index b9bf428c9..9908c7155 100644 --- a/packages/common/test/TreeShaking.test.ts +++ b/packages/common/test/TreeShaking.test.ts @@ -216,7 +216,7 @@ describe("tree-shaking", () => { }, "task-example": { "gzip": 5692, - "raw": 15390, + "raw": 15511, }, "type-object": { "gzip": 2006, @@ -231,7 +231,16 @@ describe("tree-shaking", () => { compatTest( "bundle runtime compatibility (compat lane)", async () => { - if (!isBunRuntime || process.platform === "win32") return; + if (process.platform === "win32") { + throw new Error( + `EVOLU_TREE_SHAKING_COMPAT is enabled, but platform ${process.platform} is unsupported.`, + ); + } + if (!isBunRuntime) { + throw new Error( + `EVOLU_TREE_SHAKING_COMPAT is enabled, but isBunRuntime=${String(isBunRuntime)}.`, + ); + } const fixtures = getFixtures(); for (const fixture of fixtures) { diff --git a/packages/common/test/WebSocket.test.ts b/packages/common/test/WebSocket.test.ts index 42dbc7bc1..bf2d5bbc2 100644 --- a/packages/common/test/WebSocket.test.ts +++ b/packages/common/test/WebSocket.test.ts @@ -41,7 +41,9 @@ afterEach(async () => { } }); -const wsTest = isServer ? test : test.skip; +const browserWsEnabled = + typeof process !== "undefined" && process.env?.EVOLU_BROWSER_WS_TESTS === "1"; +const wsTest = isServer || browserWsEnabled ? test : test.skip; wsTest("connects, receives message, sends message, and disposes", async () => { await using run = createRunner(); diff --git a/packages/common/test/_globalSetup.ts b/packages/common/test/_globalSetup.ts index b7fe59c10..7ec66d4a4 100644 --- a/packages/common/test/_globalSetup.ts +++ b/packages/common/test/_globalSetup.ts @@ -18,15 +18,19 @@ const closeWithTimeout = ( ): Promise => new Promise((resolve) => { let settled = false; + let timeout: ReturnType | undefined; const settle = () => { if (settled) return; settled = true; + if (timeout !== undefined) { + clearTimeout(timeout); + } resolve(); }; - close(settle); - const timeout = setTimeout(settle, timeoutMs); + timeout = setTimeout(settle, timeoutMs); timeout.unref?.(); + close(settle); }); /** diff --git a/packages/nodejs/package.json b/packages/nodejs/package.json index d38a0f1b1..e6eebd3b1 100644 --- a/packages/nodejs/package.json +++ b/packages/nodejs/package.json @@ -23,7 +23,7 @@ "README.md" ], "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage" }, diff --git a/packages/nodejs/test/Relay.test.ts b/packages/nodejs/test/Relay.test.ts index 1e5f36b18..dd7ffe908 100644 --- a/packages/nodejs/test/Relay.test.ts +++ b/packages/nodejs/test/Relay.test.ts @@ -188,8 +188,9 @@ describe("startRelay (nodejs adapter)", () => { const ws = new WebSocket(`ws://127.0.0.1:${port}?ownerId=not-owner-id`); const error = await waitForError(ws); + // Runtime-dependent: ws may report an HTTP status error or a generic close. expect(String(error.message)).toMatch( - /Unexpected server response: 400|Connection ended/, + /Unexpected server response: 40[01]|Connection ended/, ); await closeSocket(ws); }); @@ -216,8 +217,9 @@ describe("startRelay (nodejs adapter)", () => { `ws://127.0.0.1:${port}?ownerId=${testAppOwner.id}`, ); const error = await waitForError(ws); + // Runtime-dependent: ws may report an HTTP status error or a generic close. expect(String(error.message)).toMatch( - /Unexpected server response: 401|Connection ended/, + /Unexpected server response: 40[01]|Connection ended/, ); await closeSocket(ws); }); diff --git a/packages/vue/package.json b/packages/vue/package.json index 4f2def066..a1ae052f1 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -30,7 +30,7 @@ "README.md" ], "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "prepack": "bun run build", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist" }, diff --git a/packages/web/package.json b/packages/web/package.json index 054c538c1..93b902b07 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -29,7 +29,7 @@ "README.md" ], "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "bun ../../scripts/rm.mts dist && tsc --build tsconfig.build.json", "prepack": "bun run build", "dev": "tsc --build", "clean": "bun ../../scripts/rm.mts .turbo node_modules dist coverage" diff --git a/scripts/rm.mts b/scripts/rm.mts index a65bce8a4..b943c515d 100644 --- a/scripts/rm.mts +++ b/scripts/rm.mts @@ -1,13 +1,14 @@ import { rm } from "node:fs/promises"; const targets = process.argv.slice(2); +const scriptName = process.argv[1] ?? "scripts/rm.mts"; if (targets.length === 0) { - console.error("Usage: bun ./scripts/rm.mts [ ...]"); + console.error(`Usage: bun ${scriptName} [ ...]`); process.exit(1); } -await Promise.all( +const results = await Promise.allSettled( targets.map((target) => rm(target, { force: true, @@ -17,3 +18,27 @@ await Promise.all( }), ), ); + +const failedTargets: Array<{ readonly target: string; readonly error: unknown }> = + []; + +for (let i = 0; i < results.length; i++) { + const result = results[i]; + if (result?.status === "fulfilled") { + continue; + } + + failedTargets.push({ + target: targets[i] ?? "", + error: result?.reason, + }); +} + +if (failedTargets.length > 0) { + console.error(`Failed to remove ${failedTargets.length} target(s):`); + for (const failedTarget of failedTargets) { + console.error(`- ${failedTarget.target}`); + console.error(failedTarget.error); + } + process.exit(1); +} From 26323ab901555c5167da970ece8708bea83d91f0 Mon Sep 17 00:00:00 2001 From: Miccy Date: Thu, 5 Mar 2026 11:53:32 +0100 Subject: [PATCH 14/15] chore: Update dependencies across Angular, Electron, Expo, and Tanstack examples. --- bun.lock | 42 ++++++++++++++------------ examples/angular-vite-pwa/package.json | 6 ++-- examples/react-electron/package.json | 2 +- examples/react-expo/package.json | 4 +-- examples/tanstack-start/package.json | 2 +- packages/react-native/package.json | 2 +- 6 files changed, 30 insertions(+), 28 deletions(-) diff --git a/bun.lock b/bun.lock index 53acb7d70..cc1b9adf4 100644 --- a/bun.lock +++ b/bun.lock @@ -35,15 +35,15 @@ "name": "@example/angular-vite-pwa", "version": "0.0.0", "dependencies": { - "@angular/core": "^21.1.5", - "@angular/platform-browser": "^21.1.5", + "@angular/core": "^21.2.1", + "@angular/platform-browser": "^21.2.1", "@evolu/common": "workspace:*", "@evolu/web": "workspace:*", }, "devDependencies": { "@analogjs/vite-plugin-angular": "^2.3.1", "@angular/build": "^21.1.5", - "@angular/compiler-cli": "^21.1.5", + "@angular/compiler-cli": "^21.2.1", "@tailwindcss/vite": "^4.2.1", "@vite-pwa/assets-generator": "^1.0.2", "tailwindcss": "^4.2.1", @@ -82,7 +82,7 @@ "@types/react": "~19.2.14", "@types/react-dom": "~19.2.3", "@vitejs/plugin-react": "^5.1.4", - "electron": "40.6.1", + "electron": "40.7.0", "electron-builder": "^26.8.1", "typescript": "^5.9.3", "vite": "^7.3.1", @@ -102,11 +102,11 @@ "@expo/vector-icons": "^15.1.1", "abort-signal-polyfill": "^1.0.0", "babel-plugin-module-resolver": "^5.0.2", - "expo": "^55.0.4", + "expo": "^55.0.5", "expo-constants": "^55.0.7", "expo-font": "^55.0.4", "expo-linking": "^55.0.7", - "expo-router": "^55.0.3", + "expo-router": "^55.0.4", "expo-secure-store": "~55.0.8", "expo-splash-screen": "~55.0.10", "expo-sqlite": "~55.0.10", @@ -210,7 +210,7 @@ "version": "0.0.0", "dependencies": { "@evolu/tanstack-start": "workspace:*", - "@tanstack/react-router": "^1.0.0", + "@tanstack/react-router": "^1.166.2", "react": "19.2.4", "react-dom": "19.2.4", }, @@ -360,7 +360,7 @@ "@evolu/tsconfig": "workspace:*", "@op-engineering/op-sqlite": "^15.2.2", "@types/react": "~19.2.14", - "expo": "^55.0.4", + "expo": "^55.0.5", "expo-secure-store": "~55.0.8", "expo-sqlite": "~55.0.10", "react": "19.2.4", @@ -531,11 +531,11 @@ "@angular/compiler": ["@angular/compiler@21.2.0", "", { "dependencies": { "tslib": "^2.3.0" } }, "sha512-0RPkma8UVNpse/VJcXT9w6SKzTMz4J/uMGj0l9enM1frg9xrx1fwi/lLmaVV9Nr9LfqPjQdxNFFlvaBB7g/2zg=="], - "@angular/compiler-cli": ["@angular/compiler-cli@21.2.0", "", { "dependencies": { "@babel/core": "7.29.0", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^5.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^18.0.0" }, "peerDependencies": { "@angular/compiler": "21.2.0", "typescript": ">=5.9 <6.1" }, "optionalPeers": ["typescript"], "bin": { "ngc": "bundles/src/bin/ngc.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-gZd58p0/JjgdxMX3v+LjCB6e3dBIfNVr/YzXoh55TfffdBCUQY94hl1+DFQkJ72K5EX+1zbaz03dIm30kw1bGw=="], + "@angular/compiler-cli": ["@angular/compiler-cli@21.2.1", "", { "dependencies": { "@babel/core": "7.29.0", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^5.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^18.0.0" }, "peerDependencies": { "@angular/compiler": "21.2.1", "typescript": ">=5.9 <6.1" }, "optionalPeers": ["typescript"], "bin": { "ngc": "bundles/src/bin/ngc.js", "ng-xi18n": "bundles/src/bin/ng_xi18n.js" } }, "sha512-qYCWLGtEju4cDtYLi4ZzbwKoF0lcGs+Lc31kuESvAzYvWNgk2EUOtwWo8kbgpAzAwSYodtxW6Q90iWEwfU6elw=="], - "@angular/core": ["@angular/core@21.2.0", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/compiler": "21.2.0", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, "optionalPeers": ["@angular/compiler", "zone.js"] }, "sha512-VnTbmZq3g3Q+s3nCZ8VUDMLjMezOg/bqUxAJ/DrRWCrEcTP5JO3mrNPs3FHj+qlB0T+BQP7uQv6QTzPVKybwoA=="], + "@angular/core": ["@angular/core@21.2.1", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/compiler": "21.2.1", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, "optionalPeers": ["@angular/compiler", "zone.js"] }, "sha512-pFTbg03s2ZI5cHNT+eWsGjwIIKiYkeAnodFbCAHjwFi9KCEYlTykFLjr9lcpGrBddfmAH7GE08Q73vgmsdcNHw=="], - "@angular/platform-browser": ["@angular/platform-browser@21.2.0", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "21.2.0", "@angular/common": "21.2.0", "@angular/core": "21.2.0" }, "optionalPeers": ["@angular/animations"] }, "sha512-IUGukpvvT2B5Dl76qzk6rY7UIHUT9u4BhT2AwVz+5JqcX9KwQtYD17Gt7wj6bvIgCXKWG+CfN8Zd9DECOCYWjg=="], + "@angular/platform-browser": ["@angular/platform-browser@21.2.1", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "21.2.1", "@angular/common": "21.2.1", "@angular/core": "21.2.1" }, "optionalPeers": ["@angular/animations"] }, "sha512-k4SJLxIaLT26vLjLuFL+ho0BiG5PrdxEsjsXFC7w5iUhomeouzkHVTZ4t7gaLNKrdRD7QNtU4Faw0nL0yx0ZPQ=="], "@apideck/better-ajv-errors": ["@apideck/better-ajv-errors@0.3.6", "", { "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA=="], @@ -993,7 +993,7 @@ "@expo-google-fonts/material-symbols": ["@expo-google-fonts/material-symbols@0.4.24", "", {}, "sha512-1bJ63Yv2Bn8SN2MjrlbwLwUhnC8COOeejd15H88WjCtw5iNErqEPaBnpvmYyqciVYwudGo5drUIdY9C/5yPGbg=="], - "@expo/cli": ["@expo/cli@55.0.14", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~55.0.8", "@expo/config-plugins": "~55.0.6", "@expo/devcert": "^1.2.1", "@expo/env": "~2.1.1", "@expo/image-utils": "^0.8.12", "@expo/json-file": "^10.0.12", "@expo/log-box": "55.0.7", "@expo/metro": "~54.2.0", "@expo/metro-config": "~55.0.9", "@expo/osascript": "^2.4.2", "@expo/package-manager": "^1.10.3", "@expo/plist": "^0.5.2", "@expo/prebuild-config": "^55.0.8", "@expo/require-utils": "^55.0.2", "@expo/router-server": "^55.0.9", "@expo/schema-utils": "^55.0.2", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.4.0", "@react-native/dev-middleware": "0.83.2", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "dnssd-advertise": "^1.1.3", "expo-server": "^55.0.6", "fetch-nodeshim": "^0.4.6", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.2.0", "multitars": "^0.2.3", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^4.0.3", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "resolve-from": "^5.0.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "terminal-link": "^2.1.1", "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", "ws": "^8.12.1", "zod": "^3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "build/bin/cli" } }, "sha512-glXPSjjLCIz+KX/ezqLTGIF9eTE1lexiCxunvB3loRZNnGeBDGW3eF++cuPKudW26jeC6bqZkcqBG7Lp0Sp9qg=="], + "@expo/cli": ["@expo/cli@55.0.15", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~55.0.8", "@expo/config-plugins": "~55.0.6", "@expo/devcert": "^1.2.1", "@expo/env": "~2.1.1", "@expo/image-utils": "^0.8.12", "@expo/json-file": "^10.0.12", "@expo/log-box": "55.0.7", "@expo/metro": "~54.2.0", "@expo/metro-config": "~55.0.9", "@expo/osascript": "^2.4.2", "@expo/package-manager": "^1.10.3", "@expo/plist": "^0.5.2", "@expo/prebuild-config": "^55.0.8", "@expo/require-utils": "^55.0.2", "@expo/router-server": "^55.0.9", "@expo/schema-utils": "^55.0.2", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.4.0", "@react-native/dev-middleware": "0.83.2", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "dnssd-advertise": "^1.1.3", "expo-server": "^55.0.6", "fetch-nodeshim": "^0.4.6", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.2.0", "multitars": "^0.2.3", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^4.0.3", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "resolve-from": "^5.0.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "terminal-link": "^2.1.1", "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", "ws": "^8.12.1", "zod": "^3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "build/bin/cli" } }, "sha512-Qd4aF2+wT9LtdV7G/gULbx/t8FJ/OVtwuNkLcZt1XlosQ5XX/C/3ywZXYl+/bYcHUmuO1TBD3Fg05bNlmL6vrw=="], "@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.6", "", { "dependencies": { "node-forge": "^1.3.3" } }, "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w=="], @@ -1545,11 +1545,11 @@ "@tanstack/history": ["@tanstack/history@1.161.4", "", {}, "sha512-Kp/WSt411ZWYvgXy6uiv5RmhHrz9cAml05AQPrtdAp7eUqvIDbMGPnML25OKbzR3RJ1q4wgENxDTvlGPa9+Mww=="], - "@tanstack/react-router": ["@tanstack/react-router@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/react-store": "^0.9.1", "@tanstack/router-core": "1.163.3", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-hheBbFVb+PbxtrWp8iy6+TTRTbhx3Pn6hKo8Tv/sWlG89ZMcD1xpQWzx8ukHN9K8YWbh5rdzt4kv6u8X4kB28Q=="], + "@tanstack/react-router": ["@tanstack/react-router@1.166.2", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/react-store": "^0.9.1", "@tanstack/router-core": "1.166.2", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-pKhUtrvVLlhjWhsHkJSuIzh1J4LcP+8ErbIqRLORX9Js8dUFMKoT0+8oFpi+P8QRpuhm/7rzjYiWfcyTsqQZtA=="], "@tanstack/react-store": ["@tanstack/react-store@0.9.1", "", { "dependencies": { "@tanstack/store": "0.9.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-YzJLnRvy5lIEFTLWBAZmcOjK3+2AepnBv/sr6NZmiqJvq7zTQggyK99Gw8fqYdMdHPQWXjz0epFKJXC+9V2xDA=="], - "@tanstack/router-core": ["@tanstack/router-core@1.163.3", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-jPptiGq/w3nuPzcMC7RNa79aU+b6OjaDzWJnBcV2UAwL4ThJamRS4h42TdhJE+oF5yH9IEnCOGQdfnbw45LbfA=="], + "@tanstack/router-core": ["@tanstack/router-core@1.166.2", "", { "dependencies": { "@tanstack/history": "1.161.4", "@tanstack/store": "^0.9.1", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-zn3NhENOAX9ToQiX077UV2OH3aJKOvV2ZMNZZxZ3gDG3i3WqL8NfWfEgetEAfMN37/Mnt90PpotYgf7IyuoKqQ=="], "@tanstack/store": ["@tanstack/store@0.9.1", "", {}, "sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg=="], @@ -2117,7 +2117,7 @@ "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], - "electron": ["electron@40.6.1", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-u9YfoixttdauciHV9Ut9Zf3YipJoU093kR1GSYTTXTAXqhiXI0G1A0NnL/f0O2m2UULCXaXMf2W71PloR6V9pQ=="], + "electron": ["electron@40.7.0", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-oQe76S/3V1rcb0+i45hAxnCH8udkRZSaHUNwglzNAEKbB94LSJ1qwbFo8+uRc2UsYZgCqSIMRcyX40GyOkD+Xw=="], "electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="], @@ -2203,7 +2203,7 @@ "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], - "expo": ["expo@55.0.4", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "55.0.14", "@expo/config": "~55.0.8", "@expo/config-plugins": "~55.0.6", "@expo/devtools": "55.0.2", "@expo/fingerprint": "0.16.5", "@expo/local-build-cache-provider": "55.0.6", "@expo/log-box": "55.0.7", "@expo/metro": "~54.2.0", "@expo/metro-config": "55.0.9", "@expo/vector-icons": "^15.0.2", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~55.0.10", "expo-asset": "~55.0.8", "expo-constants": "~55.0.7", "expo-file-system": "~55.0.10", "expo-font": "~55.0.4", "expo-keep-awake": "~55.0.4", "expo-modules-autolinking": "55.0.8", "expo-modules-core": "55.0.13", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.1" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-cbQBPYwmH6FRvh942KR8mSdEcrVdsIMkjdHthtf59zlpzgrk28FabhOdL/Pc9WuS+CsIP3EIQbZqmLkTjv6qPg=="], + "expo": ["expo@55.0.5", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "55.0.15", "@expo/config": "~55.0.8", "@expo/config-plugins": "~55.0.6", "@expo/devtools": "55.0.2", "@expo/fingerprint": "0.16.5", "@expo/local-build-cache-provider": "55.0.6", "@expo/log-box": "55.0.7", "@expo/metro": "~54.2.0", "@expo/metro-config": "55.0.9", "@expo/vector-icons": "^15.0.2", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~55.0.10", "expo-asset": "~55.0.8", "expo-constants": "~55.0.7", "expo-file-system": "~55.0.10", "expo-font": "~55.0.4", "expo-keep-awake": "~55.0.4", "expo-modules-autolinking": "55.0.8", "expo-modules-core": "55.0.14", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.1" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-toVYbRU0gH50QSlIyrAswXD87RKi2pcJcHZpBDuqU3mIQZzJkTcWgRLWN/2R/wnd3kuJTtW5xlr5ndVG6xEWxQ=="], "expo-asset": ["expo-asset@55.0.8", "", { "dependencies": { "@expo/image-utils": "^0.8.12", "expo-constants": "~55.0.7" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-yEz2svDX67R0yiW2skx6dJmcE0q7sj9ECpGMcxBExMCbctc+nMoZCnjUuhzPl5vhClUsO5HFFXS5vIGmf1bgHQ=="], @@ -2215,7 +2215,7 @@ "expo-glass-effect": ["expo-glass-effect@55.0.7", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-G7Q9rUaEY0YC36fGE6irDljfsfvzz/y49zagARAKvSJSyQMUSrhR25WOr5LK5Cw7gQNNBEy9U1ctlr7yCay/fQ=="], - "expo-image": ["expo-image@55.0.5", "", { "dependencies": { "sf-symbols-typescript": "^2.2.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-oejmMwy5O9EtC8po9NxkcurWHqND6p8xuJaj9FGNo8NXLt9e+w3cKWx7HuPzkH5y3qFXQ9Od+z+I/wxEci36fw=="], + "expo-image": ["expo-image@55.0.6", "", { "dependencies": { "sf-symbols-typescript": "^2.2.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-TKuu0uBmgTZlhd91Glv+V4vSBMlfl0bdQxfl97oKKZUo3OBC13l3eLik7v3VNLJN7PZbiwOAiXkZkqSOBx/Xsw=="], "expo-keep-awake": ["expo-keep-awake@55.0.4", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-vwfdMtMS5Fxaon8gC0AiE70SpxTsHJ+rjeoVJl8kdfdbxczF7OIaVmfjFJ5Gfigd/WZiLqxhfZk34VAkXF4PNg=="], @@ -2223,9 +2223,9 @@ "expo-modules-autolinking": ["expo-modules-autolinking@55.0.8", "", { "dependencies": { "@expo/require-utils": "^55.0.2", "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "commander": "^7.2.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-nrWB1pkNp7bR8ECUTgYUiJ2Pyh6AvxCBXZ+lyPlfl1TzEIGhwU1Yqr+d78eJDueXaW+9zKeE0HqrTZoLS3ve4A=="], - "expo-modules-core": ["expo-modules-core@55.0.13", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-DYLQTOJAR7jD3M9S0sH9myZaPEtShdicHrPiWcupIXMeMkQxFzErx+adUI8gZPy4AU45BgeGgtaogRfT25iLfw=="], + "expo-modules-core": ["expo-modules-core@55.0.14", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-eAerOnnhbZitUAKbY7B61kIudiabAz/m/oMGINms2+GeY1DRhdvrm5aAkhkHHmykPrg58PPryXtmF14YAYWViw=="], - "expo-router": ["expo-router@55.0.3", "", { "dependencies": { "@expo/metro-runtime": "^55.0.6", "@expo/schema-utils": "^55.0.2", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.10.1", "@react-navigation/native": "^7.1.28", "@react-navigation/native-stack": "^7.10.1", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^55.0.7", "expo-image": "^55.0.5", "expo-server": "^55.0.6", "expo-symbols": "^55.0.4", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.2.1", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@expo/log-box": "55.0.7", "@react-navigation/drawer": "^7.7.2", "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^55.0.7", "expo-linking": "^55.0.7", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-B3MQAeZq9B2SS5kgEybGqXYR0AY7QYM7fQ5E4bJwtvZLJjWPmWhDALhBpD26ovK/i1k0fi9VgW47FKJODxM5Jg=="], + "expo-router": ["expo-router@55.0.4", "", { "dependencies": { "@expo/metro-runtime": "^55.0.6", "@expo/schema-utils": "^55.0.2", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-navigation/bottom-tabs": "^7.10.1", "@react-navigation/native": "^7.1.28", "@react-navigation/native-stack": "^7.10.1", "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^55.0.7", "expo-image": "^55.0.6", "expo-server": "^55.0.6", "expo-symbols": "^55.0.5", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-native-is-edge-to-edge": "^1.2.1", "semver": "~7.6.3", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "use-latest-callback": "^0.2.1", "vaul": "^1.1.2" }, "peerDependencies": { "@expo/log-box": "55.0.7", "@react-navigation/drawer": "^7.7.2", "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^55.0.7", "expo-linking": "^55.0.7", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-screens": "*", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@react-navigation/drawer", "@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-wLKxc9l3IaE96UJFvwXKi2YYYjYK/VUttwAwcnljaUA2dLgDruNGmjsBS9A+g3aK3lt2/JJRu+cec7ZLJ9r6Wg=="], "expo-secure-store": ["expo-secure-store@55.0.8", "", { "peerDependencies": { "expo": "*" } }, "sha512-8w9tQe8U6oRo5YIzqCqVhRrOnfoODNDoitBtLXEx+zS6WLUnkRq5kH7ViJuOgiM7PzLr9pvAliRiDOKyvFbTuQ=="], @@ -2235,7 +2235,7 @@ "expo-sqlite": ["expo-sqlite@55.0.10", "", { "dependencies": { "await-lock": "^2.2.2" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-yLQXkwcA0OVSKuL4t+a6vv+H/Klh8147n7hH75AN0MkC48p3Go7+6GM+3SFENeaBUsmOnOS3XSFxMxxj6PIg4g=="], - "expo-symbols": ["expo-symbols@55.0.4", "", { "dependencies": { "@expo-google-fonts/material-symbols": "^0.4.1", "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", "expo-font": "*", "react": "*", "react-native": "*" } }, "sha512-w9rxPlpta3gks0G4Tvpq/qQdiMp4R/XOeOzyjSruYUQakmsWbQBKA+Sd/fCVXs7qFJSvVTOGXiOhZm+YJRYZVg=="], + "expo-symbols": ["expo-symbols@55.0.5", "", { "dependencies": { "@expo-google-fonts/material-symbols": "^0.4.1", "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", "expo-font": "*", "react": "*", "react-native": "*" } }, "sha512-W/QYRvnYVes947ZYOHtuKL8Gobs7BUjeu9oknzbo4jGnou7Ks6bj1CwdT0ZWNBgaTopbS4/POXumJIkW4cTPSQ=="], "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], @@ -3805,6 +3805,8 @@ "@angular-devkit/core/source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + "@angular/common/@angular/core": ["@angular/core@21.2.0", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/compiler": "21.2.0", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, "optionalPeers": ["@angular/compiler", "zone.js"] }, "sha512-VnTbmZq3g3Q+s3nCZ8VUDMLjMezOg/bqUxAJ/DrRWCrEcTP5JO3mrNPs3FHj+qlB0T+BQP7uQv6QTzPVKybwoA=="], + "@angular/compiler-cli/yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], "@astrojs/react/@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], diff --git a/examples/angular-vite-pwa/package.json b/examples/angular-vite-pwa/package.json index abfd618d9..878bd5bec 100644 --- a/examples/angular-vite-pwa/package.json +++ b/examples/angular-vite-pwa/package.json @@ -9,15 +9,15 @@ "generate-pwa-assets": "pwa-assets-generator" }, "dependencies": { - "@angular/core": "^21.1.5", - "@angular/platform-browser": "^21.1.5", + "@angular/core": "^21.2.1", + "@angular/platform-browser": "^21.2.1", "@evolu/common": "workspace:*", "@evolu/web": "workspace:*" }, "devDependencies": { "@analogjs/vite-plugin-angular": "^2.3.1", "@angular/build": "^21.1.5", - "@angular/compiler-cli": "^21.1.5", + "@angular/compiler-cli": "^21.2.1", "@tailwindcss/vite": "^4.2.1", "@vite-pwa/assets-generator": "^1.0.2", "tailwindcss": "^4.2.1", diff --git a/examples/react-electron/package.json b/examples/react-electron/package.json index 038d32b36..8db825bae 100644 --- a/examples/react-electron/package.json +++ b/examples/react-electron/package.json @@ -20,7 +20,7 @@ "@types/react": "~19.2.14", "@types/react-dom": "~19.2.3", "@vitejs/plugin-react": "^5.1.4", - "electron": "40.6.1", + "electron": "40.7.0", "electron-builder": "^26.8.1", "typescript": "^5.9.3", "vite": "^7.3.1", diff --git a/examples/react-expo/package.json b/examples/react-expo/package.json index 29a97822b..a94fa1b03 100644 --- a/examples/react-expo/package.json +++ b/examples/react-expo/package.json @@ -26,11 +26,11 @@ "@expo/vector-icons": "^15.1.1", "abort-signal-polyfill": "^1.0.0", "babel-plugin-module-resolver": "^5.0.2", - "expo": "^55.0.4", + "expo": "^55.0.5", "expo-constants": "^55.0.7", "expo-font": "^55.0.4", "expo-linking": "^55.0.7", - "expo-router": "^55.0.3", + "expo-router": "^55.0.4", "expo-secure-store": "~55.0.8", "expo-splash-screen": "~55.0.10", "expo-sqlite": "~55.0.10", diff --git a/examples/tanstack-start/package.json b/examples/tanstack-start/package.json index 2585f45e1..0b3c0298b 100644 --- a/examples/tanstack-start/package.json +++ b/examples/tanstack-start/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@evolu/tanstack-start": "workspace:*", - "@tanstack/react-router": "^1.0.0", + "@tanstack/react-router": "^1.166.2", "react": "19.2.4", "react-dom": "19.2.4" }, diff --git a/packages/react-native/package.json b/packages/react-native/package.json index d4c9b7e36..97ccf5a4f 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -92,7 +92,7 @@ "@evolu/tsconfig": "workspace:*", "@op-engineering/op-sqlite": "^15.2.2", "@types/react": "~19.2.14", - "expo": "^55.0.4", + "expo": "^55.0.5", "expo-secure-store": "~55.0.8", "expo-sqlite": "~55.0.10", "react": "19.2.4", From 2f1c98bd2267bce050723db5ff6a10040f5e1e8e Mon Sep 17 00:00:00 2001 From: Miccy Date: Thu, 5 Mar 2026 12:16:20 +0100 Subject: [PATCH 15/15] Update packages/common/test/_globalSetup.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Miccy --- packages/common/test/_globalSetup.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/common/test/_globalSetup.ts b/packages/common/test/_globalSetup.ts index 7ec66d4a4..664910cfd 100644 --- a/packages/common/test/_globalSetup.ts +++ b/packages/common/test/_globalSetup.ts @@ -19,6 +19,10 @@ const closeWithTimeout = ( new Promise((resolve) => { let settled = false; let timeout: ReturnType | undefined; + const settle = () => { + if (settled) return; + let timeout: ReturnType | undefined; + const settle = () => { if (settled) return; settled = true; @@ -31,6 +35,7 @@ const closeWithTimeout = ( timeout = setTimeout(settle, timeoutMs); timeout.unref?.(); close(settle); + close(settle); }); /**