diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml new file mode 100644 index 00000000..a748766b --- /dev/null +++ b/.github/workflows/benchmarks.yml @@ -0,0 +1,42 @@ +name: Core Benchmarks + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.ref }} + cancel-in-progress: true + +jobs: + benchmarks: + name: CodSpeed CPU simulation + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Setup Node + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 + with: + node-version: 24.14.0 + - name: Setup pnpm + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0 + with: + version: 11.9.0 + cache: true + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Run benchmarks + uses: CodSpeedHQ/action@373d6868929f444bc08d901fd0eb0ad52a8875ea # v5.2.1 + with: + mode: simulation + runner-version: 5.2.1 + run: pnpm --filter @tanstack/store test:bench diff --git a/docs/reference/classes/ReadonlyStore.md b/docs/reference/classes/ReadonlyStore.md deleted file mode 100644 index 97dd2e88..00000000 --- a/docs/reference/classes/ReadonlyStore.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -id: ReadonlyStore -title: ReadonlyStore ---- - -Defined in: [store.ts:59](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L59) - -## Type Parameters - -### T - -`T` - -## Implements - -- `Omit`\<[`Store`](Store.md)\<`T`\>, `"setState"` \| `"actions"`\> - -## Constructors - -### Constructor - -```ts -new ReadonlyStore(getValue): ReadonlyStore; -``` - -Defined in: [store.ts:64](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L64) - -#### Parameters - -##### getValue - -(`prev?`) => `T` - -#### Returns - -`ReadonlyStore`\<`T`\> - -### Constructor - -```ts -new ReadonlyStore(initialValue): ReadonlyStore; -``` - -Defined in: [store.ts:65](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L65) - -#### Parameters - -##### initialValue - -`T` - -#### Returns - -`ReadonlyStore`\<`T`\> - -## Accessors - -### state - -#### Get Signature - -```ts -get state(): T; -``` - -Defined in: [store.ts:73](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L73) - -##### Returns - -`T` - -#### Implementation of - -```ts -Omit.state -``` - -## Methods - -### get() - -```ts -get(): T; -``` - -Defined in: [store.ts:76](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L76) - -#### Returns - -`T` - -#### Implementation of - -```ts -Omit.get -``` - -*** - -### subscribe() - -```ts -subscribe(observerOrFn): Subscription; -``` - -Defined in: [store.ts:79](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L79) - -#### Parameters - -##### observerOrFn - -[`Observer`](../type-aliases/Observer.md)\<`T`\> | (`value`) => `void` - -#### Returns - -[`Subscription`](../interfaces/Subscription.md) - -#### Implementation of - -```ts -Omit.subscribe -``` diff --git a/docs/reference/classes/Store.md b/docs/reference/classes/Store.md deleted file mode 100644 index 7d0eab2c..00000000 --- a/docs/reference/classes/Store.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -id: Store -title: Store ---- - -Defined in: [store.ts:15](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L15) - -## Type Parameters - -### T - -`T` - -### TActions - -`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) = `never` - -## Constructors - -### Constructor - -```ts -new Store(getValue): Store; -``` - -Defined in: [store.ts:18](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L18) - -#### Parameters - -##### getValue - -(`prev?`) => `T` - -#### Returns - -`Store`\<`T`, `TActions`\> - -### Constructor - -```ts -new Store(initialValue): Store; -``` - -Defined in: [store.ts:19](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L19) - -#### Parameters - -##### initialValue - -`T` - -#### Returns - -`Store`\<`T`, `TActions`\> - -### Constructor - -```ts -new Store(initialValue, actionsFactory): Store; -``` - -Defined in: [store.ts:20](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L20) - -#### Parameters - -##### initialValue - -`NonFunction`\<`T`\> - -##### actionsFactory - -[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> - -#### Returns - -`Store`\<`T`, `TActions`\> - -## Properties - -### actions - -```ts -readonly actions: TActions; -``` - -Defined in: [store.ts:17](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L17) - -## Accessors - -### state - -#### Get Signature - -```ts -get state(): T; -``` - -Defined in: [store.ts:46](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L46) - -##### Returns - -`T` - -## Methods - -### get() - -```ts -get(): T; -``` - -Defined in: [store.ts:49](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L49) - -#### Returns - -`T` - -*** - -### setState() - -```ts -setState(updater): void; -``` - -Defined in: [store.ts:43](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L43) - -#### Parameters - -##### updater - -(`prev`) => `T` - -#### Returns - -`void` - -*** - -### subscribe() - -```ts -subscribe(observerOrFn): Subscription; -``` - -Defined in: [store.ts:52](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L52) - -#### Parameters - -##### observerOrFn - -[`Observer`](../type-aliases/Observer.md)\<`T`\> | (`value`) => `void` - -#### Returns - -[`Subscription`](../interfaces/Subscription.md) diff --git a/docs/reference/functions/batch.md b/docs/reference/functions/batch.md deleted file mode 100644 index 43c3f38e..00000000 --- a/docs/reference/functions/batch.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: batch -title: batch ---- - -```ts -function batch(fn): void; -``` - -Defined in: [atom.ts:70](https://github.com/TanStack/store/blob/main/packages/store/src/atom.ts#L70) - -## Parameters - -### fn - -() => `void` - -## Returns - -`void` diff --git a/docs/reference/functions/createAsyncAtom.md b/docs/reference/functions/createAsyncAtom.md deleted file mode 100644 index 4bf0c602..00000000 --- a/docs/reference/functions/createAsyncAtom.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: createAsyncAtom -title: createAsyncAtom ---- - -```ts -function createAsyncAtom(getValue, options?): ReadonlyAtom>; -``` - -Defined in: [atom.ts:108](https://github.com/TanStack/store/blob/main/packages/store/src/atom.ts#L108) - -## Type Parameters - -### T - -`T` - -## Parameters - -### getValue - -() => `Promise`\<`T`\> - -### options? - -[`AtomOptions`](../interfaces/AtomOptions.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> - -## Returns - -[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`AsyncAtomState`\<`T`, `unknown`\>\> diff --git a/docs/reference/functions/createAtom.md b/docs/reference/functions/createAtom.md deleted file mode 100644 index eed96287..00000000 --- a/docs/reference/functions/createAtom.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: createAtom -title: createAtom ---- - -## Call Signature - -```ts -function createAtom(getValue, options?): ReadonlyAtom; -``` - -Defined in: [atom.ts:146](https://github.com/TanStack/store/blob/main/packages/store/src/atom.ts#L146) - -### Type Parameters - -#### T - -`T` - -### Parameters - -#### getValue - -(`prev?`) => `T` - -#### options? - -[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> - -### Returns - -[`ReadonlyAtom`](../interfaces/ReadonlyAtom.md)\<`T`\> - -## Call Signature - -```ts -function createAtom(initialValue, options?): Atom; -``` - -Defined in: [atom.ts:150](https://github.com/TanStack/store/blob/main/packages/store/src/atom.ts#L150) - -### Type Parameters - -#### T - -`T` - -### Parameters - -#### initialValue - -`T` - -#### options? - -[`AtomOptions`](../interfaces/AtomOptions.md)\<`T`\> - -### Returns - -[`Atom`](../interfaces/Atom.md)\<`T`\> diff --git a/docs/reference/functions/createStore.md b/docs/reference/functions/createStore.md deleted file mode 100644 index 827f47e2..00000000 --- a/docs/reference/functions/createStore.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -id: createStore -title: createStore ---- - -## Call Signature - -```ts -function createStore(getValue): ReadonlyStore; -``` - -Defined in: [store.ts:86](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L86) - -### Type Parameters - -#### T - -`T` - -### Parameters - -#### getValue - -(`prev?`) => `T` - -### Returns - -[`ReadonlyStore`](../classes/ReadonlyStore.md)\<`T`\> - -## Call Signature - -```ts -function createStore(initialValue): Store; -``` - -Defined in: [store.ts:89](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L89) - -### Type Parameters - -#### T - -`T` - -### Parameters - -#### initialValue - -`T` - -### Returns - -[`Store`](../classes/Store.md)\<`T`\> - -## Call Signature - -```ts -function createStore(initialValue, actions): Store; -``` - -Defined in: [store.ts:90](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L90) - -### Type Parameters - -#### T - -`T` - -#### TActions - -`TActions` *extends* [`StoreActionMap`](../type-aliases/StoreActionMap.md) - -### Parameters - -#### initialValue - -`NonFunction`\<`T`\> - -#### actions - -[`StoreActionsFactory`](../type-aliases/StoreActionsFactory.md)\<`T`, `TActions`\> - -### Returns - -[`Store`](../classes/Store.md)\<`T`, `TActions`\> diff --git a/docs/reference/functions/flush.md b/docs/reference/functions/flush.md deleted file mode 100644 index 4e1ef6c9..00000000 --- a/docs/reference/functions/flush.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: flush -title: flush ---- - -```ts -function flush(): void; -``` - -Defined in: [atom.ts:89](https://github.com/TanStack/store/blob/main/packages/store/src/atom.ts#L89) - -## Returns - -`void` diff --git a/docs/reference/functions/shallow.md b/docs/reference/functions/shallow.md deleted file mode 100644 index e371f8c1..00000000 --- a/docs/reference/functions/shallow.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: shallow -title: shallow ---- - -```ts -function shallow(objA, objB): boolean; -``` - -Defined in: [shallow.ts:1](https://github.com/TanStack/store/blob/main/packages/store/src/shallow.ts#L1) - -## Type Parameters - -### T - -`T` - -## Parameters - -### objA - -`T` - -### objB - -`T` - -## Returns - -`boolean` diff --git a/docs/reference/functions/toObserver.md b/docs/reference/functions/toObserver.md deleted file mode 100644 index b303332c..00000000 --- a/docs/reference/functions/toObserver.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: toObserver -title: toObserver ---- - -```ts -function toObserver( - nextHandler?, - errorHandler?, -completionHandler?): Observer; -``` - -Defined in: [atom.ts:20](https://github.com/TanStack/store/blob/main/packages/store/src/atom.ts#L20) - -## Type Parameters - -### T - -`T` - -## Parameters - -### nextHandler? - -[`Observer`](../type-aliases/Observer.md)\<`T`\> | (`value`) => `void` - -### errorHandler? - -(`error`) => `void` - -### completionHandler? - -() => `void` - -## Returns - -[`Observer`](../type-aliases/Observer.md)\<`T`\> diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index 9ef00a64..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: "@tanstack/store" -title: "@tanstack/store" ---- - -## Classes - -- [ReadonlyStore](classes/ReadonlyStore.md) -- [Store](classes/Store.md) - -## Interfaces - -- [Atom](interfaces/Atom.md) -- [AtomOptions](interfaces/AtomOptions.md) -- [BaseAtom](interfaces/BaseAtom.md) -- [InternalBaseAtom](interfaces/InternalBaseAtom.md) -- [InternalReadonlyAtom](interfaces/InternalReadonlyAtom.md) -- [InteropSubscribable](interfaces/InteropSubscribable.md) -- [Readable](interfaces/Readable.md) -- [ReadonlyAtom](interfaces/ReadonlyAtom.md) -- [Subscribable](interfaces/Subscribable.md) -- [Subscription](interfaces/Subscription.md) - -## Type Aliases - -- [AnyAtom](type-aliases/AnyAtom.md) -- [Observer](type-aliases/Observer.md) -- [Selection](type-aliases/Selection.md) -- [StoreAction](type-aliases/StoreAction.md) -- [StoreActionMap](type-aliases/StoreActionMap.md) -- [StoreActionsFactory](type-aliases/StoreActionsFactory.md) - -## Functions - -- [batch](functions/batch.md) -- [createAsyncAtom](functions/createAsyncAtom.md) -- [createAtom](functions/createAtom.md) -- [createStore](functions/createStore.md) -- [flush](functions/flush.md) -- [shallow](functions/shallow.md) -- [toObserver](functions/toObserver.md) diff --git a/docs/reference/interfaces/Atom.md b/docs/reference/interfaces/Atom.md deleted file mode 100644 index 279539e7..00000000 --- a/docs/reference/interfaces/Atom.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: Atom -title: Atom ---- - -Defined in: [types.ts:42](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L42) - -## Extends - -- [`BaseAtom`](BaseAtom.md)\<`T`\> - -## Type Parameters - -### T - -`T` - -## Properties - -### get() - -```ts -get: () => T; -``` - -Defined in: [types.ts:30](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L30) - -#### Returns - -`T` - -#### Inherited from - -[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) - -*** - -### set - -```ts -set: (fn) => void & (value) => void; -``` - -Defined in: [types.ts:44](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L44) - -Sets the value of the atom using a function. - -*** - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Inherited from - -[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/reference/interfaces/AtomOptions.md b/docs/reference/interfaces/AtomOptions.md deleted file mode 100644 index 1d7e29cd..00000000 --- a/docs/reference/interfaces/AtomOptions.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: AtomOptions -title: AtomOptions ---- - -Defined in: [types.ts:47](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L47) - -## Type Parameters - -### T - -`T` - -## Properties - -### compare()? - -```ts -optional compare: (prev, next) => boolean; -``` - -Defined in: [types.ts:48](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L48) - -#### Parameters - -##### prev - -`T` - -##### next - -`T` - -#### Returns - -`boolean` diff --git a/docs/reference/interfaces/BaseAtom.md b/docs/reference/interfaces/BaseAtom.md deleted file mode 100644 index 8a2a0c47..00000000 --- a/docs/reference/interfaces/BaseAtom.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -id: BaseAtom -title: BaseAtom ---- - -Defined in: [types.ts:33](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L33) - -## Extends - -- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> - -## Extended by - -- [`Atom`](Atom.md) -- [`ReadonlyAtom`](ReadonlyAtom.md) - -## Type Parameters - -### T - -`T` - -## Properties - -### get() - -```ts -get: () => T; -``` - -Defined in: [types.ts:30](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L30) - -#### Returns - -`T` - -#### Inherited from - -[`Readable`](Readable.md).[`get`](Readable.md#get) - -*** - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Inherited from - -[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/reference/interfaces/InternalBaseAtom.md b/docs/reference/interfaces/InternalBaseAtom.md deleted file mode 100644 index 33fd0bd7..00000000 --- a/docs/reference/interfaces/InternalBaseAtom.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -id: InternalBaseAtom -title: InternalBaseAtom ---- - -Defined in: [types.ts:35](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L35) - -## Extends - -- [`Subscribable`](Subscribable.md)\<`T`\>.[`Readable`](Readable.md)\<`T`\> - -## Extended by - -- [`InternalReadonlyAtom`](InternalReadonlyAtom.md) - -## Type Parameters - -### T - -`T` - -## Properties - -### \_snapshot - -```ts -_snapshot: T; -``` - -Defined in: [types.ts:37](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L37) - -**`Internal`** - -*** - -### \_update() - -```ts -_update: (getValue?) => boolean; -``` - -Defined in: [types.ts:39](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L39) - -**`Internal`** - -#### Parameters - -##### getValue? - -`T` | (`snapshot`) => `T` - -#### Returns - -`boolean` - -*** - -### get() - -```ts -get: () => T; -``` - -Defined in: [types.ts:30](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L30) - -#### Returns - -`T` - -#### Inherited from - -[`Readable`](Readable.md).[`get`](Readable.md#get) - -*** - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Inherited from - -[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/reference/interfaces/InternalReadonlyAtom.md b/docs/reference/interfaces/InternalReadonlyAtom.md deleted file mode 100644 index 44632117..00000000 --- a/docs/reference/interfaces/InternalReadonlyAtom.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -id: InternalReadonlyAtom -title: InternalReadonlyAtom ---- - -Defined in: [types.ts:53](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L53) - -## Extends - -- [`InternalBaseAtom`](InternalBaseAtom.md)\<`T`\>.`ReactiveNode` - -## Type Parameters - -### T - -`T` - -## Properties - -### \_snapshot - -```ts -_snapshot: T; -``` - -Defined in: [types.ts:37](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L37) - -**`Internal`** - -#### Inherited from - -[`InternalBaseAtom`](InternalBaseAtom.md).[`_snapshot`](InternalBaseAtom.md#_snapshot) - -*** - -### \_update() - -```ts -_update: (getValue?) => boolean; -``` - -Defined in: [types.ts:39](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L39) - -**`Internal`** - -#### Parameters - -##### getValue? - -`T` | (`snapshot`) => `T` - -#### Returns - -`boolean` - -#### Inherited from - -[`InternalBaseAtom`](InternalBaseAtom.md).[`_update`](InternalBaseAtom.md#_update) - -*** - -### deps? - -```ts -optional deps: Link; -``` - -Defined in: [alien.ts:6](https://github.com/TanStack/store/blob/main/packages/store/src/alien.ts#L6) - -#### Inherited from - -```ts -ReactiveNode.deps -``` - -*** - -### depsTail? - -```ts -optional depsTail: Link; -``` - -Defined in: [alien.ts:7](https://github.com/TanStack/store/blob/main/packages/store/src/alien.ts#L7) - -#### Inherited from - -```ts -ReactiveNode.depsTail -``` - -*** - -### flags - -```ts -flags: number; -``` - -Defined in: [alien.ts:10](https://github.com/TanStack/store/blob/main/packages/store/src/alien.ts#L10) - -#### Inherited from - -```ts -ReactiveNode.flags -``` - -*** - -### get() - -```ts -get: () => T; -``` - -Defined in: [types.ts:30](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L30) - -#### Returns - -`T` - -#### Inherited from - -[`InternalBaseAtom`](InternalBaseAtom.md).[`get`](InternalBaseAtom.md#get) - -*** - -### subs? - -```ts -optional subs: Link; -``` - -Defined in: [alien.ts:8](https://github.com/TanStack/store/blob/main/packages/store/src/alien.ts#L8) - -#### Inherited from - -```ts -ReactiveNode.subs -``` - -*** - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Inherited from - -[`InternalBaseAtom`](InternalBaseAtom.md).[`subscribe`](InternalBaseAtom.md#subscribe) - -*** - -### subsTail? - -```ts -optional subsTail: Link; -``` - -Defined in: [alien.ts:9](https://github.com/TanStack/store/blob/main/packages/store/src/alien.ts#L9) - -#### Inherited from - -```ts -ReactiveNode.subsTail -``` diff --git a/docs/reference/interfaces/InteropSubscribable.md b/docs/reference/interfaces/InteropSubscribable.md deleted file mode 100644 index f3dad5e5..00000000 --- a/docs/reference/interfaces/InteropSubscribable.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: InteropSubscribable -title: InteropSubscribable ---- - -Defined in: [types.ts:5](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L5) - -## Extended by - -- [`Subscribable`](Subscribable.md) - -## Type Parameters - -### T - -`T` - -## Properties - -### subscribe() - -```ts -subscribe: (observer) => Subscription; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L6) - -#### Parameters - -##### observer - -[`Observer`](../type-aliases/Observer.md)\<`T`\> - -#### Returns - -[`Subscription`](Subscription.md) diff --git a/docs/reference/interfaces/Readable.md b/docs/reference/interfaces/Readable.md deleted file mode 100644 index e9e84490..00000000 --- a/docs/reference/interfaces/Readable.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -id: Readable -title: Readable ---- - -Defined in: [types.ts:29](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L29) - -## Extends - -- [`Subscribable`](Subscribable.md)\<`T`\> - -## Extended by - -- [`BaseAtom`](BaseAtom.md) -- [`InternalBaseAtom`](InternalBaseAtom.md) - -## Type Parameters - -### T - -`T` - -## Properties - -### get() - -```ts -get: () => T; -``` - -Defined in: [types.ts:30](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L30) - -#### Returns - -`T` - -*** - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Inherited from - -[`Subscribable`](Subscribable.md).[`subscribe`](Subscribable.md#subscribe) diff --git a/docs/reference/interfaces/ReadonlyAtom.md b/docs/reference/interfaces/ReadonlyAtom.md deleted file mode 100644 index bc98e2de..00000000 --- a/docs/reference/interfaces/ReadonlyAtom.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -id: ReadonlyAtom -title: ReadonlyAtom ---- - -Defined in: [types.ts:67](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L67) - -An atom that is read-only and cannot be set. - -## Example - -```ts -const atom = createAtom(() => 42); -// @ts-expect-error - Cannot set a readonly atom -atom.set(43); -``` - -## Extends - -- [`BaseAtom`](BaseAtom.md)\<`T`\> - -## Type Parameters - -### T - -`T` - -## Properties - -### get() - -```ts -get: () => T; -``` - -Defined in: [types.ts:30](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L30) - -#### Returns - -`T` - -#### Inherited from - -[`BaseAtom`](BaseAtom.md).[`get`](BaseAtom.md#get) - -*** - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Inherited from - -[`BaseAtom`](BaseAtom.md).[`subscribe`](BaseAtom.md#subscribe) diff --git a/docs/reference/interfaces/Subscribable.md b/docs/reference/interfaces/Subscribable.md deleted file mode 100644 index c15ec4b5..00000000 --- a/docs/reference/interfaces/Subscribable.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: Subscribable -title: Subscribable ---- - -Defined in: [types.ts:20](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L20) - -## Extends - -- [`InteropSubscribable`](InteropSubscribable.md)\<`T`\> - -## Extended by - -- [`Readable`](Readable.md) -- [`BaseAtom`](BaseAtom.md) -- [`InternalBaseAtom`](InternalBaseAtom.md) - -## Type Parameters - -### T - -`T` - -## Properties - -### subscribe - -```ts -subscribe: (observer) => Subscription & (next, error?, complete?) => Subscription; -``` - -Defined in: [types.ts:21](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L21) - -#### Overrides - -[`InteropSubscribable`](InteropSubscribable.md).[`subscribe`](InteropSubscribable.md#subscribe) diff --git a/docs/reference/interfaces/Subscription.md b/docs/reference/interfaces/Subscription.md deleted file mode 100644 index d258cd39..00000000 --- a/docs/reference/interfaces/Subscription.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: Subscription -title: Subscription ---- - -Defined in: [types.ts:16](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L16) - -## Properties - -### unsubscribe() - -```ts -unsubscribe: () => void; -``` - -Defined in: [types.ts:17](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L17) - -#### Returns - -`void` diff --git a/docs/reference/type-aliases/AnyAtom.md b/docs/reference/type-aliases/AnyAtom.md deleted file mode 100644 index eb2c7dbd..00000000 --- a/docs/reference/type-aliases/AnyAtom.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: AnyAtom -title: AnyAtom ---- - -```ts -type AnyAtom = BaseAtom; -``` - -Defined in: [types.ts:51](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L51) diff --git a/docs/reference/type-aliases/Observer.md b/docs/reference/type-aliases/Observer.md deleted file mode 100644 index 65f901b7..00000000 --- a/docs/reference/type-aliases/Observer.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: Observer -title: Observer ---- - -```ts -type Observer = object; -``` - -Defined in: [types.ts:10](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L10) - -## Type Parameters - -### T - -`T` - -## Properties - -### complete()? - -```ts -optional complete: () => void; -``` - -Defined in: [types.ts:13](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L13) - -#### Returns - -`void` - -*** - -### error()? - -```ts -optional error: (err) => void; -``` - -Defined in: [types.ts:12](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L12) - -#### Parameters - -##### err - -`unknown` - -#### Returns - -`void` - -*** - -### next()? - -```ts -optional next: (value) => void; -``` - -Defined in: [types.ts:11](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L11) - -#### Parameters - -##### value - -`T` - -#### Returns - -`void` diff --git a/docs/reference/type-aliases/Selection.md b/docs/reference/type-aliases/Selection.md deleted file mode 100644 index 91b27b2a..00000000 --- a/docs/reference/type-aliases/Selection.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -id: Selection -title: Selection ---- - -```ts -type Selection = Readable; -``` - -Defined in: [types.ts:3](https://github.com/TanStack/store/blob/main/packages/store/src/types.ts#L3) - -## Type Parameters - -### TSelected - -`TSelected` diff --git a/docs/reference/type-aliases/StoreAction.md b/docs/reference/type-aliases/StoreAction.md deleted file mode 100644 index 645ac1cd..00000000 --- a/docs/reference/type-aliases/StoreAction.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: StoreAction -title: StoreAction ---- - -```ts -type StoreAction = (...args) => any; -``` - -Defined in: [store.ts:4](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L4) - -## Parameters - -### args - -...`any`[] - -## Returns - -`any` diff --git a/docs/reference/type-aliases/StoreActionMap.md b/docs/reference/type-aliases/StoreActionMap.md deleted file mode 100644 index fd5df617..00000000 --- a/docs/reference/type-aliases/StoreActionMap.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: StoreActionMap -title: StoreActionMap ---- - -```ts -type StoreActionMap = Record; -``` - -Defined in: [store.ts:6](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L6) diff --git a/docs/reference/type-aliases/StoreActionsFactory.md b/docs/reference/type-aliases/StoreActionsFactory.md deleted file mode 100644 index b22ccb91..00000000 --- a/docs/reference/type-aliases/StoreActionsFactory.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: StoreActionsFactory -title: StoreActionsFactory ---- - -```ts -type StoreActionsFactory = (store) => TActions; -``` - -Defined in: [store.ts:8](https://github.com/TanStack/store/blob/main/packages/store/src/store.ts#L8) - -## Type Parameters - -### T - -`T` - -### TActions - -`TActions` *extends* [`StoreActionMap`](StoreActionMap.md) - -## Parameters - -### store - -#### get - -[`Store`](../classes/Store.md)\<`T`\>\[`"get"`\] - -#### setState - -[`Store`](../classes/Store.md)\<`T`\>\[`"setState"`\] - -## Returns - -`TActions` diff --git a/packages/store/package.json b/packages/store/package.json index 10282b3b..d48d23ea 100644 --- a/packages/store/package.json +++ b/packages/store/package.json @@ -27,7 +27,7 @@ "test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js", "test:types:ts59": "tsc", "test:lib": "vitest", - "test:bench": "vitest bench", + "test:bench": "vitest bench --run --config vitest.bench.config.ts", "test:lib:dev": "pnpm run test:lib --watch", "test:build": "publint --strict", "build": "tsdown --tsconfig tsconfig.build.json" @@ -50,6 +50,7 @@ ], "devDependencies": { "@angular/core": "^21.2.8", + "@codspeed/vitest-plugin": "6.0.0-beta.2", "@preact/signals": "^2.9.0", "solid-js": "^1.9.12", "vue": "^3.5.32" diff --git a/packages/store/tests/benchmarks/README.md b/packages/store/tests/benchmarks/README.md new file mode 100644 index 00000000..67204a5a --- /dev/null +++ b/packages/store/tests/benchmarks/README.md @@ -0,0 +1,87 @@ +# Core benchmarks + +From the repository root: + +```sh +pnpm install --frozen-lockfile +pnpm --filter @tanstack/store test:bench +``` + +To focus on a group, append `--testNamePattern=unobserved`. The dedicated +`vitest.bench.config.ts` runs only this directory in Node, with coverage and +typechecking disabled. The existing `tests/derived.bench.ts` framework comparison +is excluded; its scheduling and cleanup need normalization before comparison. + +## Coverage + +The 24 cases target distinct operations and graph paths, rather than every size +combination. Fan-out uses small/large endpoints; chains use depth 100. A shallow +dependency-changed read remains because direct dirty reads differ from deep pull +validation. Inactive-branch writes are checked by the branch-switch contract. + +| Area | Cases | Measured operation | +| -------------------- | ----: | ------------------------------------------------------------------------------------------------------------ | +| Basic | 5 | Atom creation and cached get; atom/Store changed writes; atom same-value write with 100 computed subscribers | +| Fan-out | 2 | One write with 1 or 100 subscribers | +| Observed graphs | 4 | Depth-100 chain, diamond, 100-source fan-in, unchanged intermediate output | +| Unobserved | 6 | Depth-100 first/cached/dependency/unrelated reads; depth-1 dependency read; depth-100 dependency write | +| Lifecycle | 3 | Subscribe to a previously read graph, remove its last subscriber, resubscribe after an unobserved change | +| Dynamic dependencies | 1 | Switch branches | +| Batching | 2 | The same 10-source write sequence, batched and unbatched | +| Application | 1 | 200 single-field updates across 100 field selections | + +## Measurement contracts + +Fixtures are constructed outside timing, except in the creation benchmark. +Steady-state fixtures persist across invocations, and changed values toggle or +cycle deterministically. First-read graphs are freshly constructed in preparation. +In the unobserved read cases, dependency and unrelated writes happen in preparation +so timing covers only the read. The separate dependency-write case starts with a +clean, already-read graph and times invalidation without a pull read. Teardown +unsubscribes every observer. + +Each measured callback yields a small checksum. Assertions outside timing check +the returned value, notification count/sum, and relevant recomputation counts. +Same-value writes must avoid recomputation and notifications, while dependency +reads must recompute every level. Parity changes and untimed inactive-branch writes +must skip downstream work. Lifecycle verification checks notifications after a +write before reading the output, so verification cannot repair missing connections. + +The application benchmark performs a fixed sequence in every timed invocation: +update each of 100 fields to 1, then update each back to 0. Each write changes only +one field. Subscriber callbacks record a checksum and notification field, value, +and update index into preallocated buffers. Verification requires exactly one +notification from the changed field at each step and checks all final selections. +The reported cost is for all 200 updates, including object copying and notification +bookkeeping, not for one update. + +The harness uses suite hooks for CodSpeed simulation and Tinybench's public +per-iteration `Task.opts` hooks (installed by `setup`) for native Vitest. Both +runners use `setup`/`teardown` for fixture lifetime, but Vitest does not pass +per-iteration hooks through its benchmark options, and CodSpeed's simulation +runner invokes suite hooks instead. Keep both paths aligned when upgrading. +`fixtures.test.ts` also exercises each contract through four invocations in the +ordinary core test suite to cover both directions of toggles and fixture reuse. +CodSpeed simulation resets the fixture after warmup and measures one invocation; +the full application sequence is therefore timed in both local and CI runs. + +Local timing is a smoke test and exploratory measurement. Very small operations +include callback/checksum overhead, and preparation can affect cache/GC behavior. +CI uses [CodSpeed CPU simulation](https://codspeed.io/docs/instruments/cpu) for +relative CPU-cost comparisons; its reported time is not browser latency. + +## CI and baseline + +The workflow runs on pull requests, pushes to `main`, and manual dispatch. Actions, +Node, pnpm, the CodSpeed runner, and the plugin are pinned; dependency resolution +uses the frozen lockfile. `@codspeed/vitest-plugin` is pinned to `6.0.0-beta.2` +because the stable 5.x release does not declare Vite 8 support and its native +instrumentation targets older Node releases. Version 6 supports the Node 24/Vite 8 +stack used here. Revisit this pin when a compatible stable version is available. + +Enable this public repository in CodSpeed to receive uploaded reports. Public +repository uploads do not need a secret token. Initially leave performance checks +non-blocking in CodSpeed/repository branch protection and collect a `main` +baseline. Configure regression thresholds after reviewing baseline results; +execution errors and failed workload assertions should still fail the workflow. +See the [Vitest integration guide](https://codspeed.io/docs/benchmarks/nodejs/vitest). diff --git a/packages/store/tests/benchmarks/cases.ts b/packages/store/tests/benchmarks/cases.ts new file mode 100644 index 00000000..5db8ab84 --- /dev/null +++ b/packages/store/tests/benchmarks/cases.ts @@ -0,0 +1,509 @@ +import { strict as assert } from 'node:assert' +import { batch, createAtom, createStore } from '../../src' +import type { BenchmarkCase, Fixture } from './harness' +import type { ReadonlyAtom, Subscription } from '../../src' + +function chain(depth: number) { + const source = createAtom(0) + let output: ReadonlyAtom = source + let computations = 0 + for (let i = 0; i < depth; i++) { + const previous = output + output = createAtom(() => { + computations++ + return previous.get() + 1 + }) + } + return { source, output, computations: () => computations } +} + +function observe(output: ReadonlyAtom, count = 1) { + let notifications = 0 + let checksum = 0 + const subscriptions = Array.from({ length: count }, () => + output.subscribe((value) => { + notifications++ + checksum += value + }), + ) + return { + reset() { + notifications = 0 + checksum = 0 + }, + checksum: () => checksum, + verify(expectedCount: number, expectedSum: number) { + assert.equal(notifications, expectedCount) + assert.equal(checksum, expectedSum) + }, + dispose() { + subscriptions.forEach((subscription) => subscription.unsubscribe()) + }, + } +} + +function changedWrites(store: boolean): Fixture { + const state = store ? createStore(0) : createAtom(0) + const set = + 'set' in state + ? (value: number) => state.set(value) + : (value: number) => state.setState(() => value) + let next = 0 + return { + prepare() { + next = 1 - state.get() + }, + run() { + set(next) + return state.get() + }, + verify(result) { + assert.equal(result, next) + }, + } +} + +function observedGraph( + kind: 'chain' | 'diamond' | 'fan-in', + size: number, +): Fixture { + const source = createAtom(0) + let output: ReadonlyAtom + let expected: (value: number) => number + let write = (value: number) => source.set(value) + let read = () => source.get() + if (kind === 'chain') { + const graph = chain(size) + output = graph.output + write = (value) => graph.source.set(value) + read = () => graph.source.get() + expected = (value) => value + size + } else if (kind === 'diamond') { + const left = createAtom(() => source.get() + 1) + const right = createAtom(() => source.get() + 2) + output = createAtom(() => left.get() + right.get()) + expected = (value) => 2 * value + 3 + } else { + const others = Array.from({ length: size - 1 }, () => createAtom(1)) + output = createAtom( + () => source.get() + others.reduce((sum, atom) => sum + atom.get(), 0), + ) + expected = (value) => value + size - 1 + } + const observer = observe(output) + let next = 0 + return { + prepare() { + next = 1 - read() + observer.reset() + }, + run() { + write(next) + return observer.checksum() + }, + verify(result) { + assert.equal(result, expected(next)) + observer.verify(1, expected(next)) + assert.equal(output.get(), expected(next)) + }, + dispose: observer.dispose, + } +} + +function unobserved( + depth: number, + state: 'first' | 'cached' | 'dependency' | 'unrelated', +): Fixture { + let graph = chain(depth) + const unrelated = createAtom(0) + let expected = depth + let computations = 0 + return { + prepare() { + if (state === 'first') graph = chain(depth) + else { + graph.output.get() + if (state === 'dependency') graph.source.set(1 - graph.source.get()) + if (state === 'unrelated') unrelated.set(1 - unrelated.get()) + } + expected = graph.source.get() + depth + computations = graph.computations() + }, + run: () => graph.output.get(), + verify(result) { + assert.equal(result, expected) + assert.equal( + graph.computations() - computations, + state === 'first' || state === 'dependency' ? depth : 0, + ) + }, + } +} + +function lifecycle( + operation: 'subscribe' | 'unsubscribe' | 'resubscribe', +): Fixture { + const graph = chain(10) + const observer = { count: 0, sum: 0 } + const onValue = (value: number) => { + observer.count++ + observer.sum += value + } + let subscription: Subscription | undefined + let computations = 0 + return { + prepare() { + subscription?.unsubscribe() + subscription = undefined + graph.output.get() + if (operation !== 'subscribe') { + subscription = graph.output.subscribe(onValue) + if (operation === 'resubscribe') { + subscription.unsubscribe() + subscription = undefined + // Reconnect a graph that changed while it had no subscribers. + graph.source.set(1 - graph.source.get()) + } + } + observer.count = 0 + observer.sum = 0 + computations = graph.computations() + }, + run() { + if (operation === 'unsubscribe') subscription!.unsubscribe() + else subscription = graph.output.subscribe(onValue) + return observer.count + }, + verify(result) { + assert.equal(result, 0) + assert.equal( + graph.computations() - computations, + operation === 'resubscribe' ? 10 : 0, + ) + // Check reconnection before a pull read could repair missing dependencies. + graph.source.set(1 - graph.source.get()) + assert.equal(observer.count, operation === 'unsubscribe' ? 0 : 1) + assert.equal( + observer.sum, + operation === 'unsubscribe' ? 0 : graph.source.get() + 10, + ) + assert.equal(graph.output.get(), graph.source.get() + 10) + }, + dispose() { + subscription?.unsubscribe() + }, + } +} + +function dynamic(): Fixture { + const branch = createAtom(false) + const left = createAtom(10) + const right = createAtom(20) + let computations = 0 + const output = createAtom(() => { + computations++ + return branch.get() ? right.get() : left.get() + }) + const observer = observe(output) + let before = 0 + let expected = 0 + return { + prepare() { + expected = !branch.get() ? right.get() : left.get() + observer.reset() + before = computations + }, + run() { + branch.set(!branch.get()) + return observer.checksum() + }, + verify(result) { + observer.verify(1, expected) + assert.equal(result, expected) + assert.equal(output.get(), expected) + assert.equal(computations - before, 1) + + // An inactive write is a correctness check of the timed branch switch. + observer.reset() + const inactive = branch.get() ? left : right + inactive.set((value) => + value === 10 || value === 20 ? value + 1 : value - 1, + ) + observer.verify(0, 0) + assert.equal(output.get(), expected) + assert.equal(computations - before, 1) + }, + dispose: observer.dispose, + } +} + +function batching(batched: boolean): Fixture { + const sources = Array.from({ length: 10 }, () => createAtom(0)) + const output = createAtom(() => + sources.reduce((sum, source) => sum + source.get(), 0), + ) + const observer = observe(output) + let next = 0 + const write = () => { + sources.forEach((source) => source.set(next)) + } + return { + prepare() { + next = 1 - sources[0]!.get() + observer.reset() + }, + run() { + if (batched) batch(write) + else write() + return observer.checksum() + }, + verify(result) { + const expectedSum = batched ? next * 10 : next === 1 ? 55 : 45 + observer.verify(batched ? 1 : 10, expectedSum) + assert.equal(result, expectedSum) + assert.equal(output.get(), next * 10) + }, + dispose: observer.dispose, + } +} + +export const cases: Array = [ + { + name: 'basic/atom creation', + create: () => { + let created: ReturnType> + return { + run() { + created = createAtom(1) + return 1 + }, + verify(result) { + assert.equal(result, 1) + assert.equal(created.get(), 1) + }, + } + }, + }, + { + name: 'basic/atom cached get', + create: () => { + const atom = createAtom(1) + return { + run: () => atom.get(), + verify: (result) => assert.equal(result, 1), + } + }, + }, + ...[false, true].map((store) => ({ + name: `basic/${store ? 'store' : 'atom'} changed write`, + create: () => changedWrites(store), + })), + { + name: 'basic/atom same-value write with 100 computed subscribers', + create: () => { + const source = createAtom(1) + let computations = 0 + const output = createAtom(() => { + computations++ + return source.get() + 1 + }) + const observer = observe(output, 100) + return { + prepare() { + computations = 0 + observer.reset() + }, + run() { + source.set(1) + return observer.checksum() + }, + verify(result) { + assert.equal(result, 0) + observer.verify(0, 0) + assert.equal(output.get(), 2) + assert.equal(computations, 0) + }, + dispose: observer.dispose, + } + }, + }, + ...[1, 100].map((count) => ({ + name: `fan-out/${count} subscribers`, + create: (): Fixture => { + const source = createAtom(0) + const observer = observe(source, count) + let next = 0 + return { + prepare() { + next = 1 - source.get() + observer.reset() + }, + run() { + source.set(next) + return observer.checksum() + }, + verify(result) { + assert.equal(result, next * count) + observer.verify(count, next * count) + }, + dispose: observer.dispose, + } + }, + })), + { + name: 'observed/chain depth 100', + create: () => observedGraph('chain', 100), + }, + { name: 'observed/diamond', create: () => observedGraph('diamond', 0) }, + { + name: 'observed/100 sources into one computed', + create: () => observedGraph('fan-in', 100), + }, + { + name: 'observed/unchanged intermediate output', + create: () => { + const source = createAtom(0) + let downstreamRuns = 0 + let parityRuns = 0 + const parity = createAtom(() => { + parityRuns++ + return source.get() % 2 + }) + const downstream = createAtom(() => { + downstreamRuns++ + return parity.get() + 1 + }) + const observer = observe(downstream) + let next = 0 + return { + prepare() { + next = 2 - source.get() + downstreamRuns = 0 + parityRuns = 0 + observer.reset() + }, + run() { + source.set(next) + return observer.checksum() + }, + verify(result) { + assert.equal(result, 0) + observer.verify(0, 0) + assert.equal(downstream.get(), 1) + assert.equal(parityRuns, 1) + assert.equal(downstreamRuns, 0) + }, + dispose: observer.dispose, + } + }, + }, + ...(['first', 'cached', 'dependency', 'unrelated'] as const).map((state) => ({ + name: `unobserved/depth 100/${state} read`, + create: () => unobserved(100, state), + })), + { + name: 'unobserved/depth 1/dependency read', + create: () => unobserved(1, 'dependency'), + }, + { + name: 'unobserved/depth 100/dependency write', + create: () => { + const graph = chain(100) + let next = 0 + let computations = 0 + return { + prepare() { + graph.output.get() + next = 1 - graph.source.get() + computations = graph.computations() + }, + run() { + graph.source.set(next) + return next + }, + verify(result) { + assert.equal(result, next) + assert.equal(graph.source.get(), next) + assert.equal(graph.computations(), computations) + assert.equal(graph.output.get(), next + 100) + assert.equal(graph.computations() - computations, 100) + }, + } + }, + }, + ...(['subscribe', 'unsubscribe', 'resubscribe'] as const).map( + (operation) => ({ + name: `lifecycle/${operation} depth 10`, + create: () => lifecycle(operation), + }), + ), + { name: 'dynamic/switch branches', create: dynamic }, + ...[false, true].map((batched) => ({ + name: `batching/10 sources/${batched ? 'batched' : 'unbatched'}`, + create: () => batching(batched), + })), + { + name: 'application/100 field selections, 200 single-field updates', + create: () => { + const initial = Object.fromEntries( + Array.from({ length: 100 }, (_, i) => [`field${i}`, 0]), + ) + const store = createStore(initial) + const selections = Object.keys(initial).map((key) => + createAtom(() => store.get()[key]!), + ) + // Each invocation changes every field to 1, then back to 0. CodSpeed + // measures one invocation, so the complete sequence must be inside run. + const updates = [1, 0].flatMap((value) => + Object.keys(initial).map((key) => ({ key, value })), + ) + const notifiedFields = new Int32Array(updates.length) + const notifiedValues = new Int32Array(updates.length) + const notifiedSteps = new Int32Array(updates.length) + let step = 0 + let notifications = 0 + let checksum = 0 + const subscriptions = selections.map((selection, index) => + selection.subscribe((value) => { + notifiedFields[notifications] = index + notifiedValues[notifications] = value + notifiedSteps[notifications] = step + notifications++ + checksum += (index + 1) * (value + 1) + }), + ) + return { + prepare() { + notifications = 0 + checksum = 0 + notifiedFields.fill(-1) + notifiedValues.fill(-1) + notifiedSteps.fill(-1) + }, + run() { + for (step = 0; step < updates.length; step++) { + const { key, value } = updates[step]! + store.setState((previous) => ({ ...previous, [key]: value })) + } + return checksum + }, + verify(result) { + assert.equal(result, 15150) // (1 + ... + 100) * (2 + 1) + assert.equal(notifications, updates.length) + updates.forEach(({ value }, i) => { + assert.equal(notifiedFields[i], i % selections.length) + assert.equal(notifiedValues[i], value) + assert.equal(notifiedSteps[i], i) + }) + selections.forEach((selection, i) => { + assert.equal(store.get()[`field${i}`], 0) + assert.equal(selection.get(), 0) + }) + }, + dispose() { + subscriptions.forEach((subscription) => subscription.unsubscribe()) + }, + } + }, + }, +] diff --git a/packages/store/tests/benchmarks/core.bench.ts b/packages/store/tests/benchmarks/core.bench.ts new file mode 100644 index 00000000..d20f683e --- /dev/null +++ b/packages/store/tests/benchmarks/core.bench.ts @@ -0,0 +1,4 @@ +import { cases } from './cases' +import { registerBenchmark } from './harness' + +cases.forEach(registerBenchmark) diff --git a/packages/store/tests/benchmarks/fixtures.test.ts b/packages/store/tests/benchmarks/fixtures.test.ts new file mode 100644 index 00000000..57e27e51 --- /dev/null +++ b/packages/store/tests/benchmarks/fixtures.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from 'vitest' +import { cases } from './cases' + +describe('benchmark workload contracts', () => { + it('registers unique workload names', () => { + expect(new Set(cases.map(({ name }) => name)).size).toBe(cases.length) + }) + + it.each(cases)('$name', ({ create }) => { + const fixture = create() + try { + // Exercise both directions of toggles and repeated use of each fixture. + // The application workload traverses all fields twice per invocation. + for (let i = 0; i < 4; i++) { + fixture.prepare?.() + fixture.verify(fixture.run()) + } + } finally { + fixture.dispose?.() + } + }) +}) diff --git a/packages/store/tests/benchmarks/harness.ts b/packages/store/tests/benchmarks/harness.ts new file mode 100644 index 00000000..39f044a0 --- /dev/null +++ b/packages/store/tests/benchmarks/harness.ts @@ -0,0 +1,55 @@ +import { afterEach, beforeEach, bench, describe } from 'vitest' + +export interface Fixture { + prepare?: () => void + run: () => number + verify: (checksum: number) => void + dispose?: () => void +} + +export interface BenchmarkCase { + name: string + create: () => Fixture +} + +export function registerBenchmark({ name, create }: BenchmarkCase) { + describe(name, () => { + let fixture: Fixture | undefined + let checksum = 0 + + const cleanup = () => { + fixture?.dispose?.() + fixture = undefined + } + const setup = () => { + cleanup() + fixture = create() + } + const prepare = () => fixture!.prepare?.() + const verify = () => fixture!.verify(checksum) + + // CodSpeed's simulation runner uses suite hooks for each invocation. + beforeEach(prepare) + afterEach(verify) + + bench( + 'run', + () => { + checksum = fixture!.run() + }, + { + time: 100, + warmupTime: 50, + // Vitest's native runner uses Tinybench options instead of suite hooks. + // Task.opts is Tinybench's public per-iteration hook API. Installing these + // here keeps preparation/assertions outside every timed invocation. + setup(task) { + setup() + task.opts.beforeEach = prepare + task.opts.afterEach = verify + }, + teardown: cleanup, + }, + ) + }) +} diff --git a/packages/store/tsconfig.json b/packages/store/tsconfig.json index d8c62a9e..1af10c83 100644 --- a/packages/store/tsconfig.json +++ b/packages/store/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "../../tsconfig.json", - "include": ["src", "tests", "eslint.config.js", "vitest.config.ts"] + "include": ["src", "tests", "eslint.config.js", "vitest*.config.ts"] } diff --git a/packages/store/vitest.bench.config.ts b/packages/store/vitest.bench.config.ts new file mode 100644 index 00000000..b5710dce --- /dev/null +++ b/packages/store/vitest.bench.config.ts @@ -0,0 +1,14 @@ +import codspeedPlugin from '@codspeed/vitest-plugin' +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + plugins: [codspeedPlugin()], + test: { + name: '@tanstack/store benchmarks', + watch: false, + environment: 'node', + coverage: { enabled: false }, + typecheck: { enabled: false }, + benchmark: { include: ['tests/benchmarks/**/*.bench.ts'] }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19a48946..27112b5d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,7 +93,7 @@ importers: version: 8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0) vitest: specifier: ^4.1.4 - version: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) + version: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) examples/angular/atoms: dependencies: @@ -1066,7 +1066,7 @@ importers: devDependencies: '@analogjs/vite-plugin-angular': specifier: ^2.6.2 - version: 2.6.4(af0cad56f2e0b893e7378b47e734a84d) + version: 2.6.4(b6c449b3710ae548bf60447c5627efa8) '@angular/common': specifier: ^21.2.8 version: 21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2) @@ -1132,7 +1132,7 @@ importers: version: 8.58.1(eslint@10.10.0(jiti@2.6.1))(typescript@6.0.2) vitest: specifier: ^4.1.4 - version: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) + version: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) packages/react-store: dependencies: @@ -1186,6 +1186,9 @@ importers: '@angular/core': specifier: ^21.2.8 version: 21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1) + '@codspeed/vitest-plugin': + specifier: 6.0.0-beta.2 + version: 6.0.0-beta.2(tinybench@2.9.0)(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0))(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0))) '@preact/signals': specifier: ^2.9.0 version: 2.9.0(preact@10.29.1) @@ -2176,6 +2179,16 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@codspeed/core@6.0.0-beta.2': + resolution: {integrity: sha512-l/elGsNOwQV/m8PZMK0j7FHRNvFytgeSUUwUFuO6WSDZGYe3uH+da5mMjS1KpRsRElYvshkKrqvnRRqxzWQ/tQ==} + + '@codspeed/vitest-plugin@6.0.0-beta.2': + resolution: {integrity: sha512-mgSN3Cah77d84W1VFRfU3yRIz9W4rI+/sXgb8U1q6f55GyuQ3NyqB0p4lhRpzz1Oe2mRevHD0e7SkPHSOBEjyQ==} + peerDependencies: + tinybench: '>=2.9.0' + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vitest: ^3.2 || ^4 + '@csstools/color-helpers@6.0.2': resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} engines: {node: '>=20.19.0'} @@ -6131,6 +6144,10 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + flat-cache@6.1.23: resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} @@ -7029,6 +7046,10 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -7335,6 +7356,10 @@ packages: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-gyp@12.2.0: resolution: {integrity: sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==} engines: {node: ^20.17.0 || >=22.9.0} @@ -7534,6 +7559,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -7542,6 +7571,10 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-map@2.1.0: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} @@ -7613,6 +7646,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -9290,6 +9327,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + yoctocolors-cjs@2.1.3: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} @@ -9411,7 +9452,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@analogjs/vite-plugin-angular@2.6.4(af0cad56f2e0b893e7378b47e734a84d)': + '@analogjs/vite-plugin-angular@2.6.4(b6c449b3710ae548bf60447c5627efa8)': dependencies: magic-string: 0.30.21 obug: 2.2.1 @@ -9420,7 +9461,7 @@ snapshots: ts-morph: 21.0.1 optionalDependencies: '@angular-devkit/build-angular': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(lightningcss@1.33.0)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0) - '@angular/build': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(postcss@8.5.28)(terser@5.46.0)(tslib@2.8.1)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0) + '@angular/build': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(postcss@8.5.6)(terser@5.46.0)(tslib@2.8.1)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0) vite: 8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0) transitivePeerDependencies: - '@emnapi/core' @@ -9437,7 +9478,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2102.7(chokidar@5.0.0) - '@angular-devkit/build-webpack': 0.2102.7(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.3)) + '@angular-devkit/build-webpack': 0.2102.7(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.7)) '@angular-devkit/core': 21.2.7(chokidar@5.0.0) '@angular/build': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(postcss@8.5.6)(terser@5.46.0)(tslib@2.8.1)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0) '@angular/compiler-cli': 21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2) @@ -9451,35 +9492,35 @@ snapshots: '@babel/preset-env': 7.29.0(@babel/core@7.29.0) '@babel/runtime': 7.28.6 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.3)) + '@ngtools/webpack': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.7)) ansi-colors: 4.1.3 autoprefixer: 10.4.27(postcss@8.5.6) - babel-loader: 10.0.0(@babel/core@7.29.0)(webpack@5.105.2(esbuild@0.27.3)) + babel-loader: 10.0.0(@babel/core@7.29.0)(webpack@5.105.2(esbuild@0.27.7)) browserslist: 4.28.9 - copy-webpack-plugin: 14.0.0(webpack@5.105.2(esbuild@0.27.3)) - css-loader: 7.1.3(webpack@5.105.2(esbuild@0.27.3)) + copy-webpack-plugin: 14.0.0(webpack@5.105.2(esbuild@0.27.7)) + css-loader: 7.1.3(webpack@5.105.2(esbuild@0.27.7)) esbuild-wasm: 0.27.3 http-proxy-middleware: 3.0.5 istanbul-lib-instrument: 6.0.3 jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.4.2 - less-loader: 12.3.1(less@4.4.2)(webpack@5.105.2(esbuild@0.27.3)) - license-webpack-plugin: 4.0.2(webpack@5.105.2(esbuild@0.27.3)) + less-loader: 12.3.1(less@4.4.2)(webpack@5.105.2(esbuild@0.27.7)) + license-webpack-plugin: 4.0.2(webpack@5.105.2(esbuild@0.27.7)) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.10.0(webpack@5.105.2(esbuild@0.27.3)) + mini-css-extract-plugin: 2.10.0(webpack@5.105.2(esbuild@0.27.7)) open: 11.0.0 ora: 9.3.0 picomatch: 4.0.4 piscina: 5.1.4 postcss: 8.5.6 - postcss-loader: 8.2.0(postcss@8.5.6)(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.3)) + postcss-loader: 8.2.0(postcss@8.5.6)(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.7)) resolve-url-loader: 5.0.0 rxjs: 7.8.2 sass: 1.97.3 - sass-loader: 16.0.7(sass@1.97.3)(webpack@5.105.2(esbuild@0.27.3)) + sass-loader: 16.0.7(sass@1.97.3)(webpack@5.105.2(esbuild@0.27.7)) semver: 7.7.4 - source-map-loader: 5.0.0(webpack@5.105.2(esbuild@0.27.3)) + source-map-loader: 5.0.0(webpack@5.105.2(esbuild@0.27.7)) source-map-support: 0.5.21 terser: 5.46.0 tinyglobby: 0.2.15 @@ -9487,10 +9528,10 @@ snapshots: tslib: 2.8.1 typescript: 6.0.2 webpack: 5.105.2(esbuild@0.27.7) - webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)) - webpack-dev-server: 5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)) + webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)) + webpack-dev-server: 5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(webpack@5.105.2(esbuild@0.27.3)) + webpack-subresource-integrity: 5.1.0(webpack@5.105.2(esbuild@0.27.7)) optionalDependencies: '@angular/core': 21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1) '@angular/platform-browser': 21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)) @@ -9524,7 +9565,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2102.7(chokidar@5.0.0) - '@angular-devkit/build-webpack': 0.2102.7(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.3)) + '@angular-devkit/build-webpack': 0.2102.7(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.7)) '@angular-devkit/core': 21.2.7(chokidar@5.0.0) '@angular/build': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(postcss@8.5.6)(terser@5.46.0)(tslib@2.8.1)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0) '@angular/compiler-cli': 21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2) @@ -9538,35 +9579,35 @@ snapshots: '@babel/preset-env': 7.29.0(@babel/core@7.29.0) '@babel/runtime': 7.28.6 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.3)) + '@ngtools/webpack': 21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.7)) ansi-colors: 4.1.3 autoprefixer: 10.4.27(postcss@8.5.6) - babel-loader: 10.0.0(@babel/core@7.29.0)(webpack@5.105.2(esbuild@0.27.3)) + babel-loader: 10.0.0(@babel/core@7.29.0)(webpack@5.105.2(esbuild@0.27.7)) browserslist: 4.28.9 - copy-webpack-plugin: 14.0.0(webpack@5.105.2(esbuild@0.27.3)) - css-loader: 7.1.3(webpack@5.105.2(esbuild@0.27.3)) + copy-webpack-plugin: 14.0.0(webpack@5.105.2(esbuild@0.27.7)) + css-loader: 7.1.3(webpack@5.105.2(esbuild@0.27.7)) esbuild-wasm: 0.27.3 http-proxy-middleware: 3.0.5 istanbul-lib-instrument: 6.0.3 jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.4.2 - less-loader: 12.3.1(less@4.4.2)(webpack@5.105.2(esbuild@0.27.3)) - license-webpack-plugin: 4.0.2(webpack@5.105.2(esbuild@0.27.3)) + less-loader: 12.3.1(less@4.4.2)(webpack@5.105.2(esbuild@0.27.7)) + license-webpack-plugin: 4.0.2(webpack@5.105.2(esbuild@0.27.7)) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.10.0(webpack@5.105.2(esbuild@0.27.3)) + mini-css-extract-plugin: 2.10.0(webpack@5.105.2(esbuild@0.27.7)) open: 11.0.0 ora: 9.3.0 picomatch: 4.0.4 piscina: 5.1.4 postcss: 8.5.6 - postcss-loader: 8.2.0(postcss@8.5.6)(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.3)) + postcss-loader: 8.2.0(postcss@8.5.6)(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.7)) resolve-url-loader: 5.0.0 rxjs: 7.8.2 sass: 1.97.3 - sass-loader: 16.0.7(sass@1.97.3)(webpack@5.105.2(esbuild@0.27.3)) + sass-loader: 16.0.7(sass@1.97.3)(webpack@5.105.2(esbuild@0.27.7)) semver: 7.7.4 - source-map-loader: 5.0.0(webpack@5.105.2(esbuild@0.27.3)) + source-map-loader: 5.0.0(webpack@5.105.2(esbuild@0.27.7)) source-map-support: 0.5.21 terser: 5.46.0 tinyglobby: 0.2.15 @@ -9574,10 +9615,10 @@ snapshots: tslib: 2.8.1 typescript: 6.0.2 webpack: 5.105.2(esbuild@0.27.7) - webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)) - webpack-dev-server: 5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)) + webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)) + webpack-dev-server: 5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(webpack@5.105.2(esbuild@0.27.3)) + webpack-subresource-integrity: 5.1.0(webpack@5.105.2(esbuild@0.27.7)) optionalDependencies: '@angular/core': 21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1) '@angular/platform-browser': 21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)) @@ -9607,12 +9648,12 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.2102.7(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.3))': + '@angular-devkit/build-webpack@0.2102.7(chokidar@5.0.0)(webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)))(webpack@5.105.2(esbuild@0.27.7))': dependencies: '@angular-devkit/architect': 0.2102.7(chokidar@5.0.0) rxjs: 7.8.2 webpack: 5.105.2(esbuild@0.27.7) - webpack-dev-server: 5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)) + webpack-dev-server: 5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)) transitivePeerDependencies: - chokidar @@ -9642,62 +9683,6 @@ snapshots: '@angular/core': 21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1) tslib: 2.8.1 - '@angular/build@21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(postcss@8.5.28)(terser@5.46.0)(tslib@2.8.1)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0)': - dependencies: - '@ampproject/remapping': 2.3.0 - '@angular-devkit/architect': 0.2102.7(chokidar@5.0.0) - '@angular/compiler': 21.2.8 - '@angular/compiler-cli': 21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2) - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.21(@types/node@25.6.0) - '@vitejs/plugin-basic-ssl': 2.1.4(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) - beasties: 0.4.1 - browserslist: 4.28.9 - esbuild: 0.27.3 - https-proxy-agent: 7.0.6 - istanbul-lib-instrument: 6.0.3 - jsonc-parser: 3.3.1 - listr2: 9.0.5 - magic-string: 0.30.21 - mrmime: 2.0.1 - parse5-html-rewriting-stream: 8.0.0 - picomatch: 4.0.4 - piscina: 5.1.4 - rolldown: 1.0.0-rc.4(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) - sass: 1.97.3 - semver: 7.7.4 - source-map-support: 0.5.21 - tinyglobby: 0.2.15 - tslib: 2.8.1 - typescript: 6.0.2 - undici: 7.24.4 - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0) - watchpack: 2.5.1 - optionalDependencies: - '@angular/core': 21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1) - '@angular/platform-browser': 21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)) - less: 4.4.2 - lmdb: 3.5.1 - postcss: 8.5.28 - vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - '@types/node' - - chokidar - - jiti - - lightningcss - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - optional: true - '@angular/build@21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(@angular/compiler@21.2.8)(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(@angular/platform-browser@21.2.8(@angular/animations@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@angular/common@21.2.8(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1))(rxjs@7.8.2))(@angular/core@21.2.8(@angular/compiler@21.2.8)(rxjs@7.8.2)(zone.js@0.16.1)))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@25.6.0)(chokidar@5.0.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(postcss@8.5.6)(terser@5.46.0)(tslib@2.8.1)(typescript@6.0.2)(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.33.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))(yaml@2.9.0)': dependencies: '@ampproject/remapping': 2.3.0 @@ -9792,7 +9777,7 @@ snapshots: less: 4.4.2 lmdb: 3.5.1 postcss: 8.5.6 - vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' @@ -10824,6 +10809,25 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@codspeed/core@6.0.0-beta.2': + dependencies: + axios: 1.16.0 + find-up: 6.3.0 + form-data: 4.0.6 + node-gyp-build: 4.8.4 + stack-trace: 1.0.0-pre2 + transitivePeerDependencies: + - debug + + '@codspeed/vitest-plugin@6.0.0-beta.2(tinybench@2.9.0)(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0))(vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)))': + dependencies: + '@codspeed/core': 6.0.0-beta.2 + tinybench: 2.9.0 + vite: 8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0) + vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) + transitivePeerDependencies: + - debug + '@csstools/color-helpers@6.0.2': {} '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': @@ -11676,7 +11680,7 @@ snapshots: '@tybys/wasm-util': 0.10.4 optional: true - '@ngtools/webpack@21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.3))': + '@ngtools/webpack@21.2.7(@angular/compiler-cli@21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2))(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.7))': dependencies: '@angular/compiler-cli': 21.2.8(@angular/compiler@21.2.8)(typescript@6.0.2) typescript: 6.0.2 @@ -12564,7 +12568,7 @@ snapshots: svelte: 5.55.7(@typescript-eslint/types@8.58.1) optionalDependencies: vite: 8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0) - vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': dependencies: @@ -12955,7 +12959,7 @@ snapshots: magicast: 0.5.2 obug: 2.2.1 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) transitivePeerDependencies: - supports-color @@ -13432,7 +13436,7 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axios@1.16.0(debug@4.4.3): + axios@1.16.0: dependencies: follow-redirects: 1.16.0(debug@4.4.3) form-data: 4.0.6 @@ -13442,7 +13446,7 @@ snapshots: axobject-query@4.1.0: {} - babel-loader@10.0.0(@babel/core@7.29.0)(webpack@5.105.2(esbuild@0.27.3)): + babel-loader@10.0.0(@babel/core@7.29.0)(webpack@5.105.2(esbuild@0.27.7)): dependencies: '@babel/core': 7.29.0 find-up: 5.0.0 @@ -13840,7 +13844,7 @@ snapshots: dependencies: is-what: 3.14.1 - copy-webpack-plugin@14.0.0(webpack@5.105.2(esbuild@0.27.3)): + copy-webpack-plugin@14.0.0(webpack@5.105.2(esbuild@0.27.7)): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 @@ -13875,7 +13879,7 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-loader@7.1.3(webpack@5.105.2(esbuild@0.27.3)): + css-loader@7.1.3(webpack@5.105.2(esbuild@0.27.7)): dependencies: icss-utils: 5.1.0(postcss@8.5.28) postcss: 8.5.28 @@ -14850,6 +14854,11 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + find-up@6.3.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + flat-cache@6.1.23: dependencies: cacheable: 2.5.0 @@ -15588,7 +15597,7 @@ snapshots: picocolors: 1.1.1 shell-quote: 1.8.3 - less-loader@12.3.1(less@4.4.2)(webpack@5.105.2(esbuild@0.27.3)): + less-loader@12.3.1(less@4.4.2)(webpack@5.105.2(esbuild@0.27.7)): dependencies: less: 4.4.2 optionalDependencies: @@ -15613,7 +15622,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - license-webpack-plugin@4.0.2(webpack@5.105.2(esbuild@0.27.3)): + license-webpack-plugin@4.0.2(webpack@5.105.2(esbuild@0.27.7)): dependencies: webpack-sources: 3.3.4 optionalDependencies: @@ -15741,6 +15750,10 @@ snapshots: dependencies: p-locate: 5.0.0 + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + lodash.debounce@4.0.8: {} lodash.memoize@4.1.2: {} @@ -15900,7 +15913,7 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.10.0(webpack@5.105.2(esbuild@0.27.3)): + mini-css-extract-plugin@2.10.0(webpack@5.105.2(esbuild@0.27.7)): dependencies: schema-utils: 4.3.3 tapable: 2.3.2 @@ -16038,6 +16051,8 @@ snapshots: detect-libc: 2.1.2 optional: true + node-gyp-build@4.8.4: {} + node-gyp@12.2.0: dependencies: env-paths: 2.2.1 @@ -16135,7 +16150,7 @@ snapshots: ansi-styles: 4.3.0 argparse: 2.0.1 asynckit: 0.4.0 - axios: 1.16.0(debug@4.4.3) + axios: 1.16.0 balanced-match: 4.0.3 base64-js: 1.5.1 bl: 4.1.0 @@ -16452,6 +16467,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -16460,6 +16479,10 @@ snapshots: dependencies: p-limit: 3.1.0 + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + p-map@2.1.0: {} p-map@7.0.4: {} @@ -16548,6 +16571,8 @@ snapshots: path-exists@4.0.0: {} + path-exists@5.0.0: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -16604,7 +16629,7 @@ snapshots: optionalDependencies: postcss: 8.5.28 - postcss-loader@8.2.0(postcss@8.5.6)(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.3)): + postcss-loader@8.2.0(postcss@8.5.6)(typescript@6.0.2)(webpack@5.105.2(esbuild@0.27.7)): dependencies: cosmiconfig: 9.0.1(typescript@6.0.2) jiti: 2.6.1 @@ -17079,7 +17104,7 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@16.0.7(sass@1.97.3)(webpack@5.105.2(esbuild@0.27.3)): + sass-loader@16.0.7(sass@1.97.3)(webpack@5.105.2(esbuild@0.27.7)): dependencies: neo-async: 2.6.2 optionalDependencies: @@ -17372,7 +17397,7 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.105.2(esbuild@0.27.3)): + source-map-loader@5.0.0(webpack@5.105.2(esbuild@0.27.7)): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 @@ -18036,7 +18061,7 @@ snapshots: - msw optional: true - vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4)(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@25.6.0)(@vitest/coverage-istanbul@4.1.4(vitest@4.1.11))(jsdom@29.0.2(@noble/hashes@2.2.0))(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.11 '@vitest/mocker': 4.1.11(vite@8.3.0(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.4.2)(sass@1.97.3)(terser@5.46.0)(yaml@2.9.0)) @@ -18136,7 +18161,7 @@ snapshots: webidl-conversions@8.0.1: {} - webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)): + webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)): dependencies: colorette: 2.0.20 memfs: 4.57.1(tslib@2.8.1) @@ -18149,7 +18174,7 @@ snapshots: transitivePeerDependencies: - tslib - webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)): + webpack-dev-server@5.2.3(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -18177,7 +18202,7 @@ snapshots: serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.3)) + webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(esbuild@0.27.7)) ws: 8.20.0 optionalDependencies: webpack: 5.105.2(esbuild@0.27.7) @@ -18196,7 +18221,7 @@ snapshots: webpack-sources@3.3.4: {} - webpack-subresource-integrity@5.1.0(webpack@5.105.2(esbuild@0.27.3)): + webpack-subresource-integrity@5.1.0(webpack@5.105.2(esbuild@0.27.7)): dependencies: typed-assert: 1.0.9 webpack: 5.105.2(esbuild@0.27.7) @@ -18398,6 +18423,8 @@ snapshots: yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + yoctocolors-cjs@2.1.3: {} yoctocolors@2.1.2: {}